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