• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.biometrics;
18 
19 import static android.hardware.biometrics.BiometricAuthenticator.TYPE_CREDENTIAL;
20 import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
21 import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
22 import static android.hardware.biometrics.BiometricAuthenticator.TYPE_IRIS;
23 import static android.hardware.biometrics.BiometricAuthenticator.TYPE_NONE;
24 
25 import android.annotation.IntDef;
26 import android.annotation.NonNull;
27 import android.app.admin.DevicePolicyManager;
28 import android.app.trust.ITrustManager;
29 import android.content.Context;
30 import android.hardware.biometrics.BiometricAuthenticator;
31 import android.hardware.biometrics.BiometricManager;
32 import android.hardware.biometrics.PromptInfo;
33 import android.os.RemoteException;
34 import android.util.Pair;
35 import android.util.Slog;
36 
37 import com.android.server.biometrics.sensors.LockoutTracker;
38 
39 import java.lang.annotation.Retention;
40 import java.lang.annotation.RetentionPolicy;
41 import java.util.ArrayList;
42 import java.util.List;
43 
44 /**
45  * Class representing the calling client's request. Additionally, derives/calculates
46  * preliminary info that would be useful in helping serve this request. Note that generating
47  * the PreAuthInfo should not change any sensor state.
48  */
49 class PreAuthInfo {
50     static final int AUTHENTICATOR_OK = 1;
51     static final int BIOMETRIC_NO_HARDWARE = 2;
52     static final int BIOMETRIC_DISABLED_BY_DEVICE_POLICY = 3;
53     static final int BIOMETRIC_INSUFFICIENT_STRENGTH = 4;
54     static final int BIOMETRIC_INSUFFICIENT_STRENGTH_AFTER_DOWNGRADE = 5;
55     static final int BIOMETRIC_HARDWARE_NOT_DETECTED = 6;
56     static final int BIOMETRIC_NOT_ENROLLED = 7;
57     static final int BIOMETRIC_NOT_ENABLED_FOR_APPS = 8;
58     static final int CREDENTIAL_NOT_ENROLLED = 9;
59     static final int BIOMETRIC_LOCKOUT_TIMED = 10;
60     static final int BIOMETRIC_LOCKOUT_PERMANENT = 11;
61     static final int BIOMETRIC_SENSOR_PRIVACY_ENABLED = 12;
62     private static final String TAG = "BiometricService/PreAuthInfo";
63     final boolean credentialRequested;
64     // Sensors that can be used for this request (e.g. strong enough, enrolled, enabled).
65     final List<BiometricSensor> eligibleSensors;
66     // Sensors that cannot be used for this request. Pair<BiometricSensor, AuthenticatorStatus>
67     final List<Pair<BiometricSensor, Integer>> ineligibleSensors;
68     final boolean credentialAvailable;
69     final boolean confirmationRequested;
70     final boolean ignoreEnrollmentState;
71     final int userId;
72     final Context context;
73     private final boolean mBiometricRequested;
74     private final int mBiometricStrengthRequested;
75     private final BiometricCameraManager mBiometricCameraManager;
76 
PreAuthInfo(boolean biometricRequested, int biometricStrengthRequested, boolean credentialRequested, List<BiometricSensor> eligibleSensors, List<Pair<BiometricSensor, Integer>> ineligibleSensors, boolean credentialAvailable, boolean confirmationRequested, boolean ignoreEnrollmentState, int userId, Context context, BiometricCameraManager biometricCameraManager)77     private PreAuthInfo(boolean biometricRequested, int biometricStrengthRequested,
78             boolean credentialRequested, List<BiometricSensor> eligibleSensors,
79             List<Pair<BiometricSensor, Integer>> ineligibleSensors, boolean credentialAvailable,
80             boolean confirmationRequested, boolean ignoreEnrollmentState, int userId,
81             Context context, BiometricCameraManager biometricCameraManager) {
82         mBiometricRequested = biometricRequested;
83         mBiometricStrengthRequested = biometricStrengthRequested;
84         mBiometricCameraManager = biometricCameraManager;
85         this.credentialRequested = credentialRequested;
86 
87         this.eligibleSensors = eligibleSensors;
88         this.ineligibleSensors = ineligibleSensors;
89         this.credentialAvailable = credentialAvailable;
90         this.confirmationRequested = confirmationRequested;
91         this.ignoreEnrollmentState = ignoreEnrollmentState;
92         this.userId = userId;
93         this.context = context;
94     }
95 
create(ITrustManager trustManager, DevicePolicyManager devicePolicyManager, BiometricService.SettingObserver settingObserver, List<BiometricSensor> sensors, int userId, PromptInfo promptInfo, String opPackageName, boolean checkDevicePolicyManager, Context context, BiometricCameraManager biometricCameraManager)96     static PreAuthInfo create(ITrustManager trustManager,
97             DevicePolicyManager devicePolicyManager,
98             BiometricService.SettingObserver settingObserver,
99             List<BiometricSensor> sensors,
100             int userId, PromptInfo promptInfo, String opPackageName,
101             boolean checkDevicePolicyManager, Context context,
102             BiometricCameraManager biometricCameraManager)
103             throws RemoteException {
104 
105         final boolean confirmationRequested = promptInfo.isConfirmationRequested();
106         final boolean biometricRequested = Utils.isBiometricRequested(promptInfo);
107         final int requestedStrength = Utils.getPublicBiometricStrength(promptInfo);
108         final boolean credentialRequested = Utils.isCredentialRequested(promptInfo);
109 
110         final boolean credentialAvailable = trustManager.isDeviceSecure(userId,
111                 context.getDeviceId());
112 
113         // Assuming that biometric authenticators are listed in priority-order, the rest of this
114         // function will attempt to find the first authenticator that's as strong or stronger than
115         // the requested strength, available, enrolled, and enabled. The tricky part is returning
116         // the correct error. Error strings that are modality-specific should also respect the
117         // priority-order.
118 
119         final List<BiometricSensor> eligibleSensors = new ArrayList<>();
120         final List<Pair<BiometricSensor, Integer>> ineligibleSensors = new ArrayList<>();
121 
122         if (biometricRequested) {
123             for (BiometricSensor sensor : sensors) {
124 
125                 @AuthenticatorStatus int status = getStatusForBiometricAuthenticator(
126                         devicePolicyManager, settingObserver, sensor, userId, opPackageName,
127                         checkDevicePolicyManager, requestedStrength,
128                         promptInfo.getAllowedSensorIds(),
129                         promptInfo.isIgnoreEnrollmentState(),
130                         biometricCameraManager);
131 
132                 Slog.d(TAG, "Package: " + opPackageName
133                         + " Sensor ID: " + sensor.id
134                         + " Modality: " + sensor.modality
135                         + " Status: " + status);
136 
137                 // A sensor with privacy enabled will still be eligible to
138                 // authenticate with biometric prompt. This is so the framework can display
139                 // a sensor privacy error message to users after briefly showing the
140                 // Biometric Prompt.
141                 //
142                 // Note: if only a certain sensor is required and the privacy is enabled,
143                 // canAuthenticate() will return false.
144                 if (status == AUTHENTICATOR_OK) {
145                     eligibleSensors.add(sensor);
146                 } else {
147                     ineligibleSensors.add(new Pair<>(sensor, status));
148                 }
149             }
150         }
151 
152         return new PreAuthInfo(biometricRequested, requestedStrength, credentialRequested,
153                 eligibleSensors, ineligibleSensors, credentialAvailable, confirmationRequested,
154                 promptInfo.isIgnoreEnrollmentState(), userId, context, biometricCameraManager);
155     }
156 
157     /**
158      * Returns the status of the authenticator, with errors returned in a specific priority order.
159      * For example, {@link #BIOMETRIC_INSUFFICIENT_STRENGTH_AFTER_DOWNGRADE} is only returned
160      * if it has enrollments, and is enabled for apps.
161      *
162      * @return @AuthenticatorStatus
163      */
164     private static @AuthenticatorStatus
getStatusForBiometricAuthenticator( DevicePolicyManager devicePolicyManager, BiometricService.SettingObserver settingObserver, BiometricSensor sensor, int userId, String opPackageName, boolean checkDevicePolicyManager, int requestedStrength, @NonNull List<Integer> requestedSensorIds, boolean ignoreEnrollmentState, BiometricCameraManager biometricCameraManager)165     int getStatusForBiometricAuthenticator(
166             DevicePolicyManager devicePolicyManager,
167             BiometricService.SettingObserver settingObserver,
168             BiometricSensor sensor, int userId, String opPackageName,
169             boolean checkDevicePolicyManager, int requestedStrength,
170             @NonNull List<Integer> requestedSensorIds,
171             boolean ignoreEnrollmentState, BiometricCameraManager biometricCameraManager) {
172 
173         if (!requestedSensorIds.isEmpty() && !requestedSensorIds.contains(sensor.id)) {
174             return BIOMETRIC_NO_HARDWARE;
175         }
176 
177         if (sensor.modality == TYPE_FACE && biometricCameraManager.isAnyCameraUnavailable()) {
178             return BIOMETRIC_HARDWARE_NOT_DETECTED;
179         }
180 
181         final boolean wasStrongEnough =
182                 Utils.isAtLeastStrength(sensor.oemStrength, requestedStrength);
183         final boolean isStrongEnough =
184                 Utils.isAtLeastStrength(sensor.getCurrentStrength(), requestedStrength);
185 
186         if (wasStrongEnough && !isStrongEnough) {
187             return BIOMETRIC_INSUFFICIENT_STRENGTH_AFTER_DOWNGRADE;
188         } else if (!wasStrongEnough) {
189             return BIOMETRIC_INSUFFICIENT_STRENGTH;
190         }
191 
192         try {
193             if (!sensor.impl.isHardwareDetected(opPackageName)) {
194                 return BIOMETRIC_HARDWARE_NOT_DETECTED;
195             }
196 
197             if (!sensor.impl.hasEnrolledTemplates(userId, opPackageName)
198                     && !ignoreEnrollmentState) {
199                 return BIOMETRIC_NOT_ENROLLED;
200             }
201 
202             if (biometricCameraManager != null && sensor.modality == TYPE_FACE) {
203                 if (biometricCameraManager.isCameraPrivacyEnabled()) {
204                     //Camera privacy is enabled as the access is disabled
205                     return BIOMETRIC_SENSOR_PRIVACY_ENABLED;
206                 }
207             }
208 
209             final @LockoutTracker.LockoutMode int lockoutMode =
210                     sensor.impl.getLockoutModeForUser(userId);
211             if (lockoutMode == LockoutTracker.LOCKOUT_TIMED) {
212                 return BIOMETRIC_LOCKOUT_TIMED;
213             } else if (lockoutMode == LockoutTracker.LOCKOUT_PERMANENT) {
214                 return BIOMETRIC_LOCKOUT_PERMANENT;
215             }
216         } catch (RemoteException e) {
217             return BIOMETRIC_HARDWARE_NOT_DETECTED;
218         }
219 
220         if (!isEnabledForApp(settingObserver, sensor.modality, userId)) {
221             return BIOMETRIC_NOT_ENABLED_FOR_APPS;
222         }
223 
224         if (checkDevicePolicyManager) {
225             if (isBiometricDisabledByDevicePolicy(devicePolicyManager, sensor.modality, userId)) {
226                 return BIOMETRIC_DISABLED_BY_DEVICE_POLICY;
227             }
228         }
229 
230         return AUTHENTICATOR_OK;
231     }
232 
isEnabledForApp(BiometricService.SettingObserver settingObserver, @BiometricAuthenticator.Modality int modality, int userId)233     private static boolean isEnabledForApp(BiometricService.SettingObserver settingObserver,
234             @BiometricAuthenticator.Modality int modality, int userId) {
235         return settingObserver.getEnabledForApps(userId);
236     }
237 
isBiometricDisabledByDevicePolicy( DevicePolicyManager devicePolicyManager, @BiometricAuthenticator.Modality int modality, int effectiveUserId)238     private static boolean isBiometricDisabledByDevicePolicy(
239             DevicePolicyManager devicePolicyManager, @BiometricAuthenticator.Modality int modality,
240             int effectiveUserId) {
241         final int biometricToCheck = mapModalityToDevicePolicyType(modality);
242         if (biometricToCheck == DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE) {
243             throw new IllegalStateException("Modality unknown to devicePolicyManager: " + modality);
244         }
245         final int devicePolicyDisabledFeatures =
246                 devicePolicyManager.getKeyguardDisabledFeatures(null, effectiveUserId);
247         final boolean isBiometricDisabled =
248                 (biometricToCheck & devicePolicyDisabledFeatures) != 0;
249         Slog.w(TAG, "isBiometricDisabledByDevicePolicy(" + modality + "," + effectiveUserId
250                 + ")=" + isBiometricDisabled);
251         return isBiometricDisabled;
252     }
253 
254     /**
255      * @param modality one of {@link BiometricAuthenticator#TYPE_FINGERPRINT},
256      *                 {@link BiometricAuthenticator#TYPE_IRIS} or
257      *                 {@link BiometricAuthenticator#TYPE_FACE}
258      */
mapModalityToDevicePolicyType(int modality)259     private static int mapModalityToDevicePolicyType(int modality) {
260         switch (modality) {
261             case TYPE_FINGERPRINT:
262                 return DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT;
263             case TYPE_IRIS:
264                 return DevicePolicyManager.KEYGUARD_DISABLE_IRIS;
265             case TYPE_FACE:
266                 return DevicePolicyManager.KEYGUARD_DISABLE_FACE;
267             default:
268                 Slog.e(TAG, "Error modality=" + modality);
269                 return DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE;
270         }
271     }
272 
calculateErrorByPriority()273     private Pair<BiometricSensor, Integer> calculateErrorByPriority() {
274         Pair<BiometricSensor, Integer> sensorNotEnrolled = null;
275         Pair<BiometricSensor, Integer> sensorLockout = null;
276         Pair<BiometricSensor, Integer> hardwareNotDetected = null;
277         for (Pair<BiometricSensor, Integer> pair : ineligibleSensors) {
278             final int status = pair.second;
279             if (status == BIOMETRIC_LOCKOUT_TIMED || status == BIOMETRIC_LOCKOUT_PERMANENT) {
280                 sensorLockout = pair;
281             }
282             if (status == BIOMETRIC_NOT_ENROLLED) {
283                 sensorNotEnrolled = pair;
284             }
285             if (status == BIOMETRIC_HARDWARE_NOT_DETECTED) {
286                 hardwareNotDetected = pair;
287             }
288         }
289 
290         // If there is a sensor locked out, prioritize lockout over other sensor's error.
291         // See b/286923477.
292         if (sensorLockout != null) {
293             return sensorLockout;
294         }
295 
296         if (hardwareNotDetected != null) {
297             return hardwareNotDetected;
298         }
299 
300         // If the caller requested STRONG, and the device contains both STRONG and non-STRONG
301         // sensors, prioritize BIOMETRIC_NOT_ENROLLED over the weak sensor's
302         // BIOMETRIC_INSUFFICIENT_STRENGTH error.
303         if (sensorNotEnrolled != null) {
304             return sensorNotEnrolled;
305         }
306         return ineligibleSensors.get(0);
307     }
308 
309     /**
310      * With {@link PreAuthInfo} generated with the requested authenticators from the public API
311      * surface, combined with the actual sensor/credential and user/system settings, calculate the
312      * internal {@link AuthenticatorStatus} that should be returned to the client. Note that this
313      * will need to be converted into the public API constant.
314      *
315      * @return Pair<Modality, Error> with error being the internal {@link AuthenticatorStatus} code
316      */
getInternalStatus()317     private Pair<Integer, Integer> getInternalStatus() {
318         @AuthenticatorStatus final int status;
319         @BiometricAuthenticator.Modality int modality = TYPE_NONE;
320 
321         boolean cameraPrivacyEnabled = false;
322         if (mBiometricCameraManager != null) {
323             cameraPrivacyEnabled = mBiometricCameraManager.isCameraPrivacyEnabled();
324         }
325 
326         if (mBiometricRequested && credentialRequested) {
327             if (credentialAvailable || !eligibleSensors.isEmpty()) {
328                 for (BiometricSensor sensor : eligibleSensors) {
329                     modality |= sensor.modality;
330                 }
331 
332                 if (credentialAvailable) {
333                     modality |= TYPE_CREDENTIAL;
334                     status = AUTHENTICATOR_OK;
335                 } else if (modality == TYPE_FACE && cameraPrivacyEnabled) {
336                     // If the only modality requested is face, credential is unavailable,
337                     // and the face sensor privacy is enabled then return
338                     // BIOMETRIC_SENSOR_PRIVACY_ENABLED.
339                     //
340                     // Note: This sensor will not be eligible for calls to authenticate.
341                     status = BIOMETRIC_SENSOR_PRIVACY_ENABLED;
342                 } else {
343                     status = AUTHENTICATOR_OK;
344                 }
345             } else {
346                 // Pick the first sensor error if it exists
347                 if (!ineligibleSensors.isEmpty()) {
348                     final Pair<BiometricSensor, Integer> pair = calculateErrorByPriority();
349                     modality |= pair.first.modality;
350                     status = pair.second;
351                 } else {
352                     modality |= TYPE_CREDENTIAL;
353                     status = CREDENTIAL_NOT_ENROLLED;
354                 }
355             }
356         } else if (mBiometricRequested) {
357             if (!eligibleSensors.isEmpty()) {
358                 for (BiometricSensor sensor : eligibleSensors) {
359                     modality |= sensor.modality;
360                 }
361                 if (modality == TYPE_FACE && cameraPrivacyEnabled) {
362                     // If the only modality requested is face and the privacy is enabled
363                     // then return BIOMETRIC_SENSOR_PRIVACY_ENABLED.
364                     //
365                     // Note: This sensor will not be eligible for calls to authenticate.
366                     status = BIOMETRIC_SENSOR_PRIVACY_ENABLED;
367                 } else {
368                     status = AUTHENTICATOR_OK;
369                 }
370             } else {
371                 // Pick the first sensor error if it exists
372                 if (!ineligibleSensors.isEmpty()) {
373                     final Pair<BiometricSensor, Integer> pair = calculateErrorByPriority();
374                     modality |= pair.first.modality;
375                     status = pair.second;
376                 } else {
377                     modality |= TYPE_NONE;
378                     status = BIOMETRIC_NO_HARDWARE;
379                 }
380             }
381         } else if (credentialRequested) {
382             modality |= TYPE_CREDENTIAL;
383             status = credentialAvailable ? AUTHENTICATOR_OK : CREDENTIAL_NOT_ENROLLED;
384         } else {
385             // This should not be possible via the public API surface and is here mainly for
386             // "correctness". An exception should have been thrown before getting here.
387             Slog.e(TAG, "No authenticators requested");
388             status = BIOMETRIC_NO_HARDWARE;
389         }
390         Slog.d(TAG, "getCanAuthenticateInternal Modality: " + modality
391                 + " AuthenticatorStatus: " + status);
392 
393         return new Pair<>(modality, status);
394     }
395 
396     /**
397      * @return public BiometricManager result for the current request.
398      */
399     @BiometricManager.BiometricError
getCanAuthenticateResult()400     int getCanAuthenticateResult() {
401         // TODO: Convert this directly
402         return Utils.biometricConstantsToBiometricManager(
403                 Utils.authenticatorStatusToBiometricConstant(
404                         getInternalStatus().second));
405     }
406 
407     /**
408      * For the given request, generate the appropriate reason why authentication cannot be started.
409      * Note that for some errors, modality is intentionally cleared.
410      *
411      * @return Pair<Modality, Error> with modality being filtered if necessary, and error
412      * being one of the public {@link android.hardware.biometrics.BiometricConstants} codes.
413      */
getPreAuthenticateStatus()414     Pair<Integer, Integer> getPreAuthenticateStatus() {
415         final Pair<Integer, Integer> internalStatus = getInternalStatus();
416 
417         final int publicError = Utils.authenticatorStatusToBiometricConstant(internalStatus.second);
418         int modality = internalStatus.first;
419         switch (internalStatus.second) {
420             case AUTHENTICATOR_OK:
421             case BIOMETRIC_NO_HARDWARE:
422             case BIOMETRIC_INSUFFICIENT_STRENGTH_AFTER_DOWNGRADE:
423             case BIOMETRIC_HARDWARE_NOT_DETECTED:
424             case BIOMETRIC_NOT_ENROLLED:
425             case CREDENTIAL_NOT_ENROLLED:
426             case BIOMETRIC_LOCKOUT_TIMED:
427             case BIOMETRIC_LOCKOUT_PERMANENT:
428             case BIOMETRIC_SENSOR_PRIVACY_ENABLED:
429                 break;
430 
431             case BIOMETRIC_DISABLED_BY_DEVICE_POLICY:
432             case BIOMETRIC_INSUFFICIENT_STRENGTH:
433             case BIOMETRIC_NOT_ENABLED_FOR_APPS:
434             default:
435                 modality = TYPE_NONE;
436                 break;
437         }
438 
439         return new Pair<>(modality, publicError);
440     }
441 
442     /**
443      * @return true if SystemUI should show the credential UI.
444      */
shouldShowCredential()445     boolean shouldShowCredential() {
446         return credentialRequested && credentialAvailable;
447     }
448 
449     /**
450      * @return bitmask representing the modalities that are running or could be running for the
451      * current session.
452      */
453     @BiometricAuthenticator.Modality
getEligibleModalities()454     int getEligibleModalities() {
455         @BiometricAuthenticator.Modality int modalities = 0;
456         for (BiometricSensor sensor : eligibleSensors) {
457             modalities |= sensor.modality;
458         }
459 
460         if (credentialRequested && credentialAvailable) {
461             modalities |= TYPE_CREDENTIAL;
462         }
463         return modalities;
464     }
465 
numSensorsWaitingForCookie()466     int numSensorsWaitingForCookie() {
467         int numWaiting = 0;
468         for (BiometricSensor sensor : eligibleSensors) {
469             if (sensor.getSensorState() == BiometricSensor.STATE_WAITING_FOR_COOKIE) {
470                 Slog.d(TAG, "Sensor ID: " + sensor.id
471                         + " Waiting for cookie: " + sensor.getCookie());
472                 numWaiting++;
473             }
474         }
475         return numWaiting;
476     }
477 
478     @Override
toString()479     public String toString() {
480         StringBuilder string = new StringBuilder(
481                 "BiometricRequested: " + mBiometricRequested
482                         + ", StrengthRequested: " + mBiometricStrengthRequested
483                         + ", CredentialRequested: " + credentialRequested);
484         string.append(", Eligible:{");
485         for (BiometricSensor sensor : eligibleSensors) {
486             string.append(sensor.id).append(" ");
487         }
488         string.append("}");
489 
490         string.append(", Ineligible:{");
491         for (Pair<BiometricSensor, Integer> ineligible : ineligibleSensors) {
492             string.append(ineligible.first).append(":").append(ineligible.second).append(" ");
493         }
494         string.append("}");
495 
496         string.append(", CredentialAvailable: ").append(credentialAvailable);
497         string.append(", ");
498         return string.toString();
499     }
500 
501     @IntDef({AUTHENTICATOR_OK,
502             BIOMETRIC_NO_HARDWARE,
503             BIOMETRIC_DISABLED_BY_DEVICE_POLICY,
504             BIOMETRIC_INSUFFICIENT_STRENGTH,
505             BIOMETRIC_INSUFFICIENT_STRENGTH_AFTER_DOWNGRADE,
506             BIOMETRIC_HARDWARE_NOT_DETECTED,
507             BIOMETRIC_NOT_ENROLLED,
508             BIOMETRIC_NOT_ENABLED_FOR_APPS,
509             CREDENTIAL_NOT_ENROLLED,
510             BIOMETRIC_LOCKOUT_TIMED,
511             BIOMETRIC_LOCKOUT_PERMANENT,
512             BIOMETRIC_SENSOR_PRIVACY_ENABLED})
513     @Retention(RetentionPolicy.SOURCE)
514     @interface AuthenticatorStatus {
515     }
516 }
517