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