• 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.sensors;
18 
19 import android.annotation.NonNull;
20 import android.content.Context;
21 import android.hardware.biometrics.BiometricAuthenticator;
22 import android.os.Build;
23 import android.os.IBinder;
24 import android.util.Slog;
25 
26 import com.android.internal.annotations.VisibleForTesting;
27 import com.android.server.biometrics.BiometricsProto;
28 import com.android.server.biometrics.log.BiometricContext;
29 import com.android.server.biometrics.log.BiometricLogger;
30 
31 import java.util.ArrayList;
32 import java.util.List;
33 import java.util.Map;
34 import java.util.function.Supplier;
35 
36 /**
37  * Wraps {@link InternalEnumerateClient} and {@link RemovalClient}. Keeps track of all the
38  * internal states when cleaning up mismatch between framework and HAL templates. This client
39  * ends either when
40  * 1) The HAL and Framework are in sync, and
41  * {@link #onEnumerationResult(BiometricAuthenticator.Identifier, int)} returns true, or
42  * 2) The HAL and Framework are not in sync, and
43  * {@link #onRemoved(BiometricAuthenticator.Identifier, int)} returns true/
44  */
45 public abstract class InternalCleanupClient<S extends BiometricAuthenticator.Identifier, T>
46         extends HalClientMonitor<T> implements EnumerateConsumer, RemovalConsumer,
47         EnrollmentModifier {
48 
49     private static final String TAG = "Biometrics/InternalCleanupClient";
50 
51     /**
52      * Container for enumerated templates. Used to keep track when cleaning up unknown
53      * templates.
54      */
55     private static final class UserTemplate {
56         final BiometricAuthenticator.Identifier mIdentifier;
57         final int mUserId;
UserTemplate(BiometricAuthenticator.Identifier identifier, int userId)58         UserTemplate(BiometricAuthenticator.Identifier identifier, int userId) {
59             this.mIdentifier = identifier;
60             this.mUserId = userId;
61         }
62     }
63 
64     private final ArrayList<UserTemplate> mUnknownHALTemplates = new ArrayList<>();
65     private final BiometricUtils<S> mBiometricUtils;
66     private final Map<Integer, Long> mAuthenticatorIds;
67     private final boolean mHasEnrollmentsBeforeStarting;
68     private BaseClientMonitor mCurrentTask;
69     private boolean mFavorHalEnrollments = false;
70 
71     private final ClientMonitorCallback mEnumerateCallback = new ClientMonitorCallback() {
72         @Override
73         public void onClientFinished(@NonNull BaseClientMonitor clientMonitor, boolean success) {
74             final List<BiometricAuthenticator.Identifier> unknownHALTemplates =
75                     ((InternalEnumerateClient<T>) mCurrentTask).getUnknownHALTemplates();
76 
77             Slog.d(TAG, "Enumerate onClientFinished: " + clientMonitor + ", success: " + success);
78 
79             if (!unknownHALTemplates.isEmpty()) {
80                 Slog.w(TAG, "Adding " + unknownHALTemplates.size() + " templates for deletion");
81             }
82             for (BiometricAuthenticator.Identifier unknownHALTemplate : unknownHALTemplates) {
83                 mUnknownHALTemplates.add(new UserTemplate(unknownHALTemplate,
84                         mCurrentTask.getTargetUserId()));
85             }
86 
87             if (mUnknownHALTemplates.isEmpty()) {
88                 // No unknown HAL templates. Unknown framework templates are already cleaned up in
89                 // InternalEnumerateClient. Finish this client.
90                 mCallback.onClientFinished(InternalCleanupClient.this, success);
91             } else {
92                 if (mFavorHalEnrollments && Build.isDebuggable()) {
93                     // on debug builds, optionally allow the HAL be the source of
94                     // truth for enrollments
95                     try {
96                         for (UserTemplate template : mUnknownHALTemplates) {
97                             Slog.i(TAG, "Adding unknown HAL template: "
98                                     + template.mIdentifier.getBiometricId());
99                             onAddUnknownTemplate(template.mUserId, template.mIdentifier);
100                         }
101                     } finally {
102                         mCallback.onClientFinished(InternalCleanupClient.this, success);
103                     }
104                 } else {
105                     startCleanupUnknownHalTemplates();
106                 }
107             }
108         }
109     };
110 
111     private final ClientMonitorCallback mRemoveCallback = new ClientMonitorCallback() {
112         @Override
113         public void onClientFinished(@NonNull BaseClientMonitor clientMonitor, boolean success) {
114             Slog.d(TAG, "Remove onClientFinished: " + clientMonitor + ", success: " + success);
115             if (mUnknownHALTemplates.isEmpty()) {
116                 mCallback.onClientFinished(InternalCleanupClient.this, success);
117             } else {
118                 startCleanupUnknownHalTemplates();
119             }
120         }
121     };
122 
getEnumerateClient(Context context, Supplier<T> lazyDaemon, IBinder token, int userId, String owner, List<S> enrolledList, BiometricUtils<S> utils, int sensorId, @NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext)123     protected abstract InternalEnumerateClient<T> getEnumerateClient(Context context,
124             Supplier<T> lazyDaemon, IBinder token, int userId, String owner,
125             List<S> enrolledList, BiometricUtils<S> utils, int sensorId,
126             @NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext);
127 
getRemovalClient(Context context, Supplier<T> lazyDaemon, IBinder token, int biometricId, int userId, String owner, BiometricUtils<S> utils, int sensorId, @NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext, Map<Integer, Long> authenticatorIds)128     protected abstract RemovalClient<S, T> getRemovalClient(Context context,
129             Supplier<T> lazyDaemon, IBinder token, int biometricId, int userId, String owner,
130             BiometricUtils<S> utils, int sensorId,
131             @NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext,
132             Map<Integer, Long> authenticatorIds);
133 
InternalCleanupClient(@onNull Context context, @NonNull Supplier<T> lazyDaemon, int userId, @NonNull String owner, int sensorId, @NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext, @NonNull BiometricUtils<S> utils, @NonNull Map<Integer, Long> authenticatorIds)134     protected InternalCleanupClient(@NonNull Context context, @NonNull Supplier<T> lazyDaemon,
135             int userId, @NonNull String owner, int sensorId,
136             @NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext,
137             @NonNull BiometricUtils<S> utils,
138             @NonNull Map<Integer, Long> authenticatorIds) {
139         super(context, lazyDaemon, null /* token */, null /* ClientMonitorCallbackConverter */,
140                 userId, owner, 0 /* cookie */, sensorId, logger, biometricContext);
141         mBiometricUtils = utils;
142         mAuthenticatorIds = authenticatorIds;
143         mHasEnrollmentsBeforeStarting = !utils.getBiometricsForUser(context, userId).isEmpty();
144     }
145 
startCleanupUnknownHalTemplates()146     private void startCleanupUnknownHalTemplates() {
147         Slog.d(TAG, "startCleanupUnknownHalTemplates, size: " + mUnknownHALTemplates.size());
148 
149         UserTemplate template = mUnknownHALTemplates.get(0);
150         mUnknownHALTemplates.remove(template);
151         mCurrentTask = getRemovalClient(getContext(), mLazyDaemon, getToken(),
152                 template.mIdentifier.getBiometricId(), template.mUserId,
153                 getContext().getPackageName(), mBiometricUtils, getSensorId(),
154                 getLogger(), getBiometricContext(), mAuthenticatorIds);
155 
156         getLogger().logUnknownEnrollmentInHal();
157 
158         mCurrentTask.start(mRemoveCallback);
159     }
160 
161     @Override
unableToStart()162     public void unableToStart() {
163         // nothing to do here
164     }
165 
166     @Override
start(@onNull ClientMonitorCallback callback)167     public void start(@NonNull ClientMonitorCallback callback) {
168         super.start(callback);
169 
170         final List<S> enrolledList =
171                 mBiometricUtils.getBiometricsForUser(getContext(), getTargetUserId());
172 
173         // Start enumeration. Removal will start if necessary, when enumeration is completed.
174         mCurrentTask = getEnumerateClient(getContext(), mLazyDaemon, getToken(), getTargetUserId(),
175                 getOwnerString(), enrolledList, mBiometricUtils, getSensorId(), getLogger(),
176                 getBiometricContext());
177 
178         Slog.d(TAG, "Starting enumerate: " + mCurrentTask + " enrolledList size:"
179                 + enrolledList.size());
180         mCurrentTask.start(mEnumerateCallback);
181     }
182 
183     @Override
startHalOperation()184     protected void startHalOperation() {
185         // Internal cleanup's start method does not require a HAL operation, but rather
186         // relies on its subtask's ClientMonitor to start the proper HAL operation.
187     }
188 
189     @Override
onRemoved(BiometricAuthenticator.Identifier identifier, int remaining)190     public void onRemoved(BiometricAuthenticator.Identifier identifier, int remaining) {
191         if (!(mCurrentTask instanceof RemovalClient)) {
192             Slog.e(TAG, "onRemoved received during client: "
193                     + mCurrentTask.getClass().getSimpleName());
194             return;
195         }
196         ((RemovalClient<S, T>) mCurrentTask).onRemoved(identifier, remaining);
197     }
198 
199     @Override
hasEnrollmentStateChanged()200     public boolean hasEnrollmentStateChanged() {
201         final boolean hasEnrollmentsNow = !mBiometricUtils
202                 .getBiometricsForUser(getContext(), getTargetUserId()).isEmpty();
203         return hasEnrollmentsNow != mHasEnrollmentsBeforeStarting;
204     }
205 
206     @Override
hasEnrollments()207     public boolean hasEnrollments() {
208         return !mBiometricUtils.getBiometricsForUser(getContext(), getTargetUserId()).isEmpty();
209     }
210 
211     @Override
onEnumerationResult(BiometricAuthenticator.Identifier identifier, int remaining)212     public void onEnumerationResult(BiometricAuthenticator.Identifier identifier,
213             int remaining) {
214         if (!(mCurrentTask instanceof InternalEnumerateClient)) {
215             Slog.e(TAG, "onEnumerationResult received during client: "
216                     + mCurrentTask.getClass().getSimpleName());
217             return;
218         }
219         Slog.d(TAG, "onEnumerated, remaining: " + remaining);
220         ((EnumerateConsumer) mCurrentTask).onEnumerationResult(identifier, remaining);
221     }
222 
223     /** When set unknown templates in the HAL will be added instead of deleted. */
setFavorHalEnrollments()224     public void setFavorHalEnrollments() {
225         mFavorHalEnrollments = true;
226     }
227 
228     /** Called when an unknown template is found and setFavorHalEnrollments was requested. */
onAddUnknownTemplate(int userId, @NonNull BiometricAuthenticator.Identifier identifier)229     protected void onAddUnknownTemplate(int userId,
230             @NonNull BiometricAuthenticator.Identifier identifier) {}
231 
232     @Override
getProtoEnum()233     public int getProtoEnum() {
234         return BiometricsProto.CM_INTERNAL_CLEANUP;
235     }
236 
237     @VisibleForTesting
getCurrentEnumerateClient()238     public InternalEnumerateClient<T> getCurrentEnumerateClient() {
239         return (InternalEnumerateClient<T>) mCurrentTask;
240     }
241 
242     @VisibleForTesting
getCurrentRemoveClient()243     public RemovalClient<S, T> getCurrentRemoveClient() {
244         return (RemovalClient<S, T>) mCurrentTask;
245     }
246 
247     @VisibleForTesting
getUnknownHALTemplates()248     public ArrayList<UserTemplate> getUnknownHALTemplates() {
249         return mUnknownHALTemplates;
250     }
251 }
252