1 /*
2 * Copyright (C) 2022 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 #include <android/binder_process.h>
18 #include <face.sysprop.h>
19 #include <gtest/gtest.h>
20
21 #include <aidl/android/hardware/biometrics/face/BnSessionCallback.h>
22 #include <android-base/logging.h>
23
24 #include "FakeFaceEngine.h"
25
26 using namespace ::android::face::virt;
27 using namespace ::aidl::android::hardware::biometrics::face;
28 using namespace ::aidl::android::hardware::keymaster;
29
30 namespace aidl::android::hardware::biometrics::face {
31
32 class TestSessionCallback : public BnSessionCallback {
33 public:
onChallengeGenerated(int64_t challenge)34 ndk::ScopedAStatus onChallengeGenerated(int64_t challenge) override {
35 mLastChallenge = challenge;
36 return ndk::ScopedAStatus::ok();
37 };
onChallengeRevoked(int64_t challenge)38 ::ndk::ScopedAStatus onChallengeRevoked(int64_t challenge) override {
39 mLastChallengeRevoked = challenge;
40 return ndk::ScopedAStatus::ok();
41 };
onError(Error error,int32_t)42 ::ndk::ScopedAStatus onError(Error error, int32_t) override {
43 mError = error;
44 return ndk::ScopedAStatus::ok();
45 };
onEnrollmentProgress(int32_t enrollmentId,int32_t remaining)46 ::ndk::ScopedAStatus onEnrollmentProgress(int32_t enrollmentId, int32_t remaining) override {
47 if (remaining == 0) mLastEnrolled = enrollmentId;
48 return ndk::ScopedAStatus::ok();
49 };
50
onAuthenticationSucceeded(int32_t enrollmentId,const HardwareAuthToken &)51 ::ndk::ScopedAStatus onAuthenticationSucceeded(int32_t enrollmentId,
52 const HardwareAuthToken&) override {
53 mLastAuthenticated = enrollmentId;
54 mAuthenticateFailed = false;
55 return ndk::ScopedAStatus::ok();
56 };
onAuthenticationFailed()57 ::ndk::ScopedAStatus onAuthenticationFailed() override {
58 mLastAuthenticated = 0;
59 mAuthenticateFailed = true;
60 return ndk::ScopedAStatus::ok();
61 };
onInteractionDetected()62 ::ndk::ScopedAStatus onInteractionDetected() override {
63 mInteractionDetectedCount++;
64 return ndk::ScopedAStatus::ok();
65 };
66
onEnrollmentFrame(const EnrollmentFrame & frame)67 ::ndk::ScopedAStatus onEnrollmentFrame(const EnrollmentFrame& frame) override {
68 mEnrollmentFrames.push_back(frame.data.vendorCode);
69 return ndk::ScopedAStatus::ok();
70 }
71
onEnrollmentsEnumerated(const std::vector<int32_t> & enrollmentIds)72 ::ndk::ScopedAStatus onEnrollmentsEnumerated(
73 const std::vector<int32_t>& enrollmentIds) override {
74 mLastEnrollmentsEnumerated = enrollmentIds;
75 return ndk::ScopedAStatus::ok();
76 };
onEnrollmentsRemoved(const std::vector<int32_t> & enrollmentIds)77 ::ndk::ScopedAStatus onEnrollmentsRemoved(const std::vector<int32_t>& enrollmentIds) override {
78 mLastEnrollmentRemoved = enrollmentIds;
79 return ndk::ScopedAStatus::ok();
80 };
onAuthenticatorIdRetrieved(int64_t authenticatorId)81 ::ndk::ScopedAStatus onAuthenticatorIdRetrieved(int64_t authenticatorId) override {
82 mLastAuthenticatorId = authenticatorId;
83 return ndk::ScopedAStatus::ok();
84 };
onAuthenticatorIdInvalidated(int64_t authenticatorId)85 ::ndk::ScopedAStatus onAuthenticatorIdInvalidated(int64_t authenticatorId) override {
86 mLastAuthenticatorId = authenticatorId;
87 mAuthenticatorIdInvalidated = true;
88 return ndk::ScopedAStatus::ok();
89 };
onAuthenticationFrame(const AuthenticationFrame &)90 ::ndk::ScopedAStatus onAuthenticationFrame(const AuthenticationFrame& /*authFrame*/) override {
91 return ndk::ScopedAStatus::ok();
92 }
onLockoutPermanent()93 ::ndk::ScopedAStatus onLockoutPermanent() override {
94 mLockoutPermanent = true;
95 return ndk::ScopedAStatus::ok();
96 };
onLockoutTimed(int64_t)97 ::ndk::ScopedAStatus onLockoutTimed(int64_t /* timeout */) override {
98 return ndk::ScopedAStatus::ok();
99 }
onLockoutCleared()100 ::ndk::ScopedAStatus onLockoutCleared() override {
101 mLockoutPermanent = false;
102 return ndk::ScopedAStatus::ok();
103 }
onSessionClosed()104 ::ndk::ScopedAStatus onSessionClosed() override { return ndk::ScopedAStatus::ok(); }
105
onFeaturesRetrieved(const std::vector<Feature> & features)106 ::ndk::ScopedAStatus onFeaturesRetrieved(const std::vector<Feature>& features) override {
107 mFeatures = features;
108 return ndk::ScopedAStatus::ok();
109 }
110
onFeatureSet(Feature feature)111 ::ndk::ScopedAStatus onFeatureSet(Feature feature) override {
112 mLastFeatureSet = feature;
113 return ndk::ScopedAStatus::ok();
114 }
115
116 Error mError = Error::UNKNOWN;
117 int64_t mLastChallenge = -1;
118 int64_t mLastChallengeRevoked = -1;
119 int32_t mLastEnrolled = -1;
120 int32_t mLastAuthenticated = -1;
121 int64_t mLastAuthenticatorId = -1;
122 std::vector<int32_t> mLastEnrollmentsEnumerated;
123 std::vector<int32_t> mLastEnrollmentRemoved;
124 std::vector<Feature> mFeatures;
125 Feature mLastFeatureSet;
126 std::vector<int32_t> mEnrollmentFrames;
127 bool mAuthenticateFailed = false;
128 bool mAuthenticatorIdInvalidated = false;
129 bool mLockoutPermanent = false;
130 int mInteractionDetectedCount = 0;
131 };
132
133 class FakeFaceEngineTest : public ::testing::Test {
134 protected:
SetUp()135 void SetUp() override {
136 LOG(ERROR) << "JRM SETUP";
137 mCallback = ndk::SharedRefBase::make<TestSessionCallback>();
138 FaceHalProperties::enrollments({});
139 FaceHalProperties::challenge({});
140 FaceHalProperties::features({});
141 FaceHalProperties::authenticator_id({});
142 FaceHalProperties::strength("");
143 }
144
145 FakeFaceEngine mEngine;
146 std::shared_ptr<TestSessionCallback> mCallback;
147 std::promise<void> mCancel;
148 };
149
TEST_F(FakeFaceEngineTest,one_eq_one)150 TEST_F(FakeFaceEngineTest, one_eq_one) {
151 ASSERT_EQ(1, 1);
152 }
153
TEST_F(FakeFaceEngineTest,GenerateChallenge)154 TEST_F(FakeFaceEngineTest, GenerateChallenge) {
155 mEngine.generateChallengeImpl(mCallback.get());
156 ASSERT_EQ(FaceHalProperties::challenge().value(), mCallback->mLastChallenge);
157 }
158
TEST_F(FakeFaceEngineTest,RevokeChallenge)159 TEST_F(FakeFaceEngineTest, RevokeChallenge) {
160 auto challenge = FaceHalProperties::challenge().value_or(10);
161 mEngine.revokeChallengeImpl(mCallback.get(), challenge);
162 ASSERT_FALSE(FaceHalProperties::challenge().has_value());
163 ASSERT_EQ(challenge, mCallback->mLastChallengeRevoked);
164 }
165
TEST_F(FakeFaceEngineTest,ResetLockout)166 TEST_F(FakeFaceEngineTest, ResetLockout) {
167 FaceHalProperties::lockout(true);
168 mEngine.resetLockoutImpl(mCallback.get(), {});
169 ASSERT_FALSE(mCallback->mLockoutPermanent);
170 ASSERT_FALSE(FaceHalProperties::lockout().value_or(true));
171 }
172
TEST_F(FakeFaceEngineTest,AuthenticatorId)173 TEST_F(FakeFaceEngineTest, AuthenticatorId) {
174 FaceHalProperties::authenticator_id(50);
175 mEngine.getAuthenticatorIdImpl(mCallback.get());
176 ASSERT_EQ(50, mCallback->mLastAuthenticatorId);
177 ASSERT_FALSE(mCallback->mAuthenticatorIdInvalidated);
178 }
179
TEST_F(FakeFaceEngineTest,GetAuthenticatorIdWeakReturnsZero)180 TEST_F(FakeFaceEngineTest, GetAuthenticatorIdWeakReturnsZero) {
181 FaceHalProperties::strength("weak");
182 FaceHalProperties::authenticator_id(500);
183 mEngine.getAuthenticatorIdImpl(mCallback.get());
184 ASSERT_EQ(0, mCallback->mLastAuthenticatorId);
185 ASSERT_FALSE(mCallback->mAuthenticatorIdInvalidated);
186 }
187
TEST_F(FakeFaceEngineTest,AuthenticatorIdInvalidate)188 TEST_F(FakeFaceEngineTest, AuthenticatorIdInvalidate) {
189 FaceHalProperties::authenticator_id(500);
190 mEngine.invalidateAuthenticatorIdImpl(mCallback.get());
191 ASSERT_NE(500, FaceHalProperties::authenticator_id().value());
192 ASSERT_TRUE(mCallback->mAuthenticatorIdInvalidated);
193 }
194
TEST_F(FakeFaceEngineTest,Enroll)195 TEST_F(FakeFaceEngineTest, Enroll) {
196 FaceHalProperties::next_enrollment("1,0:30:true,1:0:true,2:0:true,3:0:true,4:0:true");
197 keymaster::HardwareAuthToken hat{.mac = {2, 4}};
198 mEngine.enrollImpl(mCallback.get(), hat, {} /*enrollmentType*/, {} /*features*/,
199 mCancel.get_future());
200 ASSERT_FALSE(FaceHalProperties::next_enrollment().has_value());
201 ASSERT_EQ(1, FaceHalProperties::enrollments().size());
202 ASSERT_EQ(1, FaceHalProperties::enrollments()[0].value());
203 ASSERT_EQ(1, mCallback->mLastEnrolled);
204 }
205
TEST_F(FakeFaceEngineTest,EnrollFails)206 TEST_F(FakeFaceEngineTest, EnrollFails) {
207 FaceHalProperties::next_enrollment("1,0:30:true,1:0:true,2:0:true,3:0:true,4:0:false");
208 keymaster::HardwareAuthToken hat{.mac = {2, 4}};
209 mEngine.enrollImpl(mCallback.get(), hat, {} /*enrollmentType*/, {} /*features*/,
210 mCancel.get_future());
211 ASSERT_FALSE(FaceHalProperties::next_enrollment().has_value());
212 ASSERT_EQ(0, FaceHalProperties::enrollments().size());
213 }
214
TEST_F(FakeFaceEngineTest,EnrollCancel)215 TEST_F(FakeFaceEngineTest, EnrollCancel) {
216 FaceHalProperties::next_enrollment("1,0:30:true,1:0:true,2:0:true,3:0:true,4:0:false");
217 keymaster::HardwareAuthToken hat{.mac = {2, 4}};
218 mCancel.set_value();
219 mEngine.enrollImpl(mCallback.get(), hat, {} /*enrollmentType*/, {} /*features*/,
220 mCancel.get_future());
221 ASSERT_EQ(Error::CANCELED, mCallback->mError);
222 ASSERT_EQ(-1, mCallback->mLastEnrolled);
223 ASSERT_EQ(0, FaceHalProperties::enrollments().size());
224 ASSERT_FALSE(FaceHalProperties::next_enrollment().has_value());
225 }
226
TEST_F(FakeFaceEngineTest,Authenticate)227 TEST_F(FakeFaceEngineTest, Authenticate) {
228 FaceHalProperties::enrollments({100});
229 FaceHalProperties::enrollment_hit(100);
230 mEngine.authenticateImpl(mCallback.get(), 0 /* operationId*/, mCancel.get_future());
231
232 ASSERT_EQ(100, mCallback->mLastAuthenticated);
233 ASSERT_FALSE(mCallback->mAuthenticateFailed);
234 }
235
TEST_F(FakeFaceEngineTest,AuthenticateCancel)236 TEST_F(FakeFaceEngineTest, AuthenticateCancel) {
237 FaceHalProperties::enrollments({100});
238 FaceHalProperties::enrollment_hit(100);
239 mCancel.set_value();
240 mEngine.authenticateImpl(mCallback.get(), 0 /* operationId*/, mCancel.get_future());
241 ASSERT_EQ(Error::CANCELED, mCallback->mError);
242 }
243
TEST_F(FakeFaceEngineTest,AuthenticateFailedForUnEnrolled)244 TEST_F(FakeFaceEngineTest, AuthenticateFailedForUnEnrolled) {
245 FaceHalProperties::enrollments({3});
246 FaceHalProperties::enrollment_hit(100);
247 mEngine.authenticateImpl(mCallback.get(), 0 /* operationId*/, mCancel.get_future());
248 ASSERT_EQ(Error::UNABLE_TO_PROCESS, mCallback->mError);
249 ASSERT_TRUE(mCallback->mAuthenticateFailed);
250 }
251
TEST_F(FakeFaceEngineTest,DetectInteraction)252 TEST_F(FakeFaceEngineTest, DetectInteraction) {
253 FaceHalProperties::enrollments({100});
254 FaceHalProperties::enrollment_hit(100);
255 ASSERT_EQ(0, mCallback->mInteractionDetectedCount);
256 mEngine.detectInteractionImpl(mCallback.get(), mCancel.get_future());
257 ASSERT_EQ(1, mCallback->mInteractionDetectedCount);
258 }
259
TEST_F(FakeFaceEngineTest,DetectInteractionCancel)260 TEST_F(FakeFaceEngineTest, DetectInteractionCancel) {
261 FaceHalProperties::enrollments({100});
262 FaceHalProperties::enrollment_hit(100);
263 mCancel.set_value();
264 mEngine.detectInteractionImpl(mCallback.get(), mCancel.get_future());
265 ASSERT_EQ(Error::CANCELED, mCallback->mError);
266 }
267
TEST_F(FakeFaceEngineTest,GetFeatureEmpty)268 TEST_F(FakeFaceEngineTest, GetFeatureEmpty) {
269 mEngine.getFeaturesImpl(mCallback.get());
270 ASSERT_TRUE(mCallback->mFeatures.empty());
271 }
272
TEST_F(FakeFaceEngineTest,SetFeature)273 TEST_F(FakeFaceEngineTest, SetFeature) {
274 FaceHalProperties::enrollments({1});
275 keymaster::HardwareAuthToken hat{.mac = {2, 4}};
276 mEngine.setFeatureImpl(mCallback.get(), hat, Feature::REQUIRE_ATTENTION, true);
277 auto features = mCallback->mFeatures;
278 ASSERT_TRUE(features.empty());
279 ASSERT_EQ(Feature::REQUIRE_ATTENTION, mCallback->mLastFeatureSet);
280
281 mEngine.getFeaturesImpl(mCallback.get());
282 features = mCallback->mFeatures;
283 ASSERT_FALSE(features.empty());
284 ASSERT_NE(features.end(),
285 std::find(features.begin(), features.end(), Feature::REQUIRE_ATTENTION));
286 }
287
TEST_F(FakeFaceEngineTest,ToggleFeature)288 TEST_F(FakeFaceEngineTest, ToggleFeature) {
289 FaceHalProperties::enrollments({1});
290 keymaster::HardwareAuthToken hat{.mac = {2, 4}};
291 mEngine.setFeatureImpl(mCallback.get(), hat, Feature::REQUIRE_ATTENTION, true);
292 mEngine.getFeaturesImpl(mCallback.get());
293 auto features = mCallback->mFeatures;
294 ASSERT_FALSE(features.empty());
295 ASSERT_NE(features.end(),
296 std::find(features.begin(), features.end(), Feature::REQUIRE_ATTENTION));
297
298 mEngine.setFeatureImpl(mCallback.get(), hat, Feature::REQUIRE_ATTENTION, false);
299 mEngine.getFeaturesImpl(mCallback.get());
300 features = mCallback->mFeatures;
301 ASSERT_TRUE(features.empty());
302 }
303
TEST_F(FakeFaceEngineTest,TurningOffNonExistentFeatureDoesNothing)304 TEST_F(FakeFaceEngineTest, TurningOffNonExistentFeatureDoesNothing) {
305 FaceHalProperties::enrollments({1});
306 keymaster::HardwareAuthToken hat{.mac = {2, 4}};
307 mEngine.setFeatureImpl(mCallback.get(), hat, Feature::REQUIRE_ATTENTION, false);
308 mEngine.getFeaturesImpl(mCallback.get());
309 auto features = mCallback->mFeatures;
310 ASSERT_TRUE(features.empty());
311 }
312
TEST_F(FakeFaceEngineTest,SetMultipleFeatures)313 TEST_F(FakeFaceEngineTest, SetMultipleFeatures) {
314 FaceHalProperties::enrollments({1});
315 keymaster::HardwareAuthToken hat{.mac = {2, 4}};
316 mEngine.setFeatureImpl(mCallback.get(), hat, Feature::REQUIRE_ATTENTION, true);
317 mEngine.setFeatureImpl(mCallback.get(), hat, Feature::REQUIRE_DIVERSE_POSES, true);
318 mEngine.setFeatureImpl(mCallback.get(), hat, Feature::DEBUG, true);
319 mEngine.getFeaturesImpl(mCallback.get());
320 auto features = mCallback->mFeatures;
321 ASSERT_EQ(3, features.size());
322 ASSERT_NE(features.end(),
323 std::find(features.begin(), features.end(), Feature::REQUIRE_ATTENTION));
324 ASSERT_NE(features.end(),
325 std::find(features.begin(), features.end(), Feature::REQUIRE_DIVERSE_POSES));
326 ASSERT_NE(features.end(), std::find(features.begin(), features.end(), Feature::DEBUG));
327 }
328
TEST_F(FakeFaceEngineTest,SetMultipleFeaturesAndTurnOffSome)329 TEST_F(FakeFaceEngineTest, SetMultipleFeaturesAndTurnOffSome) {
330 FaceHalProperties::enrollments({1});
331 keymaster::HardwareAuthToken hat{.mac = {2, 4}};
332 mEngine.setFeatureImpl(mCallback.get(), hat, Feature::REQUIRE_ATTENTION, true);
333 mEngine.setFeatureImpl(mCallback.get(), hat, Feature::REQUIRE_DIVERSE_POSES, true);
334 mEngine.setFeatureImpl(mCallback.get(), hat, Feature::DEBUG, true);
335 mEngine.setFeatureImpl(mCallback.get(), hat, Feature::DEBUG, false);
336 mEngine.getFeaturesImpl(mCallback.get());
337 auto features = mCallback->mFeatures;
338 ASSERT_EQ(2, features.size());
339 ASSERT_NE(features.end(),
340 std::find(features.begin(), features.end(), Feature::REQUIRE_ATTENTION));
341 ASSERT_NE(features.end(),
342 std::find(features.begin(), features.end(), Feature::REQUIRE_DIVERSE_POSES));
343 ASSERT_EQ(features.end(), std::find(features.begin(), features.end(), Feature::DEBUG));
344 }
345
TEST_F(FakeFaceEngineTest,Enumerate)346 TEST_F(FakeFaceEngineTest, Enumerate) {
347 FaceHalProperties::enrollments({120, 3});
348 mEngine.enumerateEnrollmentsImpl(mCallback.get());
349 auto enrolls = mCallback->mLastEnrollmentsEnumerated;
350 ASSERT_FALSE(enrolls.empty());
351 ASSERT_NE(enrolls.end(), std::find(enrolls.begin(), enrolls.end(), 120));
352 ASSERT_NE(enrolls.end(), std::find(enrolls.begin(), enrolls.end(), 3));
353 }
354
TEST_F(FakeFaceEngineTest,RemoveEnrollments)355 TEST_F(FakeFaceEngineTest, RemoveEnrollments) {
356 FaceHalProperties::enrollments({120, 3, 100});
357 mEngine.removeEnrollmentsImpl(mCallback.get(), {120, 100});
358 mEngine.enumerateEnrollmentsImpl(mCallback.get());
359 auto enrolls = mCallback->mLastEnrollmentsEnumerated;
360 ASSERT_FALSE(enrolls.empty());
361 ASSERT_EQ(enrolls.end(), std::find(enrolls.begin(), enrolls.end(), 120));
362 ASSERT_NE(enrolls.end(), std::find(enrolls.begin(), enrolls.end(), 3));
363 ASSERT_EQ(enrolls.end(), std::find(enrolls.begin(), enrolls.end(), 100));
364 }
365
TEST_F(FakeFaceEngineTest,ResetLockoutWithAuth)366 TEST_F(FakeFaceEngineTest, ResetLockoutWithAuth) {
367 FaceHalProperties::lockout(true);
368 FaceHalProperties::enrollments({33});
369 FaceHalProperties::enrollment_hit(33);
370 auto cancelFuture = mCancel.get_future();
371 mEngine.authenticateImpl(mCallback.get(), 0 /* operationId*/, cancelFuture);
372
373 ASSERT_TRUE(mCallback->mLockoutPermanent);
374
375 mEngine.resetLockoutImpl(mCallback.get(), {} /* hat */);
376 ASSERT_FALSE(mCallback->mLockoutPermanent);
377 FaceHalProperties::enrollment_hit(33);
378 mEngine.authenticateImpl(mCallback.get(), 0 /* operationId*/, cancelFuture);
379 ASSERT_EQ(33, mCallback->mLastAuthenticated);
380 ASSERT_FALSE(mCallback->mAuthenticateFailed);
381 }
382
383 } // namespace aidl::android::hardware::biometrics::face