1 /*
2 * Copyright (C) 2024 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 <android-base/logging.h>
22
23 #include "Face.h"
24 #include "VirtualHal.h"
25
26 using namespace ::android::face::virt;
27 using namespace ::aidl::android::hardware::biometrics::face;
28
29 namespace aidl::android::hardware::biometrics::face {
30
31 class VirtualHalTest : public ::testing::Test {
32 public:
33 static const int32_t STATUS_FAILED_TO_SET_PARAMETER = 2;
34
35 protected:
SetUp()36 void SetUp() override {
37 mHal = ndk::SharedRefBase::make<Face>();
38 mVhal = ndk::SharedRefBase::make<VirtualHal>(mHal);
39 ASSERT_TRUE(mVhal != nullptr);
40 mHal->resetConfigToDefault();
41 }
42
TearDown()43 void TearDown() override { mHal->resetConfigToDefault(); }
44
45 std::shared_ptr<VirtualHal> mVhal;
46
47 ndk::ScopedAStatus validateNonNegativeInputOfInt32(const char* name,
48 ndk::ScopedAStatus (VirtualHal::*f)(int32_t),
49 const std::vector<int32_t>& in_good);
50
51 private:
52 std::shared_ptr<Face> mHal;
53 };
54
validateNonNegativeInputOfInt32(const char * name,ndk::ScopedAStatus (VirtualHal::* f)(int32_t),const std::vector<int32_t> & in_params_good)55 ndk::ScopedAStatus VirtualHalTest::validateNonNegativeInputOfInt32(
56 const char* name, ndk::ScopedAStatus (VirtualHal::*f)(int32_t),
57 const std::vector<int32_t>& in_params_good) {
58 ndk::ScopedAStatus status;
59 for (auto& param : in_params_good) {
60 status = (*mVhal.*f)(param);
61 if (!status.isOk()) return status;
62 if (Face::cfg().get<int32_t>(name) != param) {
63 return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
64 VirtualHalTest::STATUS_FAILED_TO_SET_PARAMETER,
65 "Error: fail to set non-negative parameter"));
66 }
67 }
68
69 int32_t old_param = Face::cfg().get<int32_t>(name);
70 status = (*mVhal.*f)(-1);
71 if (status.isOk()) {
72 return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
73 VirtualHalTest::STATUS_FAILED_TO_SET_PARAMETER, "Error: should return NOK"));
74 }
75 if (status.getServiceSpecificError() != IVirtualHal::STATUS_INVALID_PARAMETER) {
76 return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
77 VirtualHalTest::STATUS_FAILED_TO_SET_PARAMETER,
78 "Error: unexpected return error code"));
79 }
80 if (Face::cfg().get<int32_t>(name) != old_param) {
81 return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
82 VirtualHalTest::STATUS_FAILED_TO_SET_PARAMETER,
83 "Error: unexpected parameter change on failed attempt"));
84 }
85 return ndk::ScopedAStatus::ok();
86 }
87
TEST_F(VirtualHalTest,init)88 TEST_F(VirtualHalTest, init) {
89 mVhal->setLockout(false);
90 ASSERT_TRUE(Face::cfg().get<bool>("lockout") == false);
91 ASSERT_TRUE(Face::cfg().get<std::string>("type") == "rgb");
92 ASSERT_TRUE(Face::cfg().get<std::string>("strength") == "strong");
93 std::int64_t id = Face::cfg().get<std::int64_t>("authenticator_id");
94 ASSERT_TRUE(Face::cfg().get<std::int64_t>("authenticator_id") == 0);
95 ASSERT_TRUE(Face::cfg().getopt<OptIntVec>("enrollments") == OptIntVec());
96 }
97
TEST_F(VirtualHalTest,enrollment_hit_int32)98 TEST_F(VirtualHalTest, enrollment_hit_int32) {
99 mVhal->setEnrollmentHit(11);
100 ASSERT_TRUE(Face::cfg().get<int32_t>("enrollment_hit") == 11);
101 }
102
TEST_F(VirtualHalTest,next_enrollment)103 TEST_F(VirtualHalTest, next_enrollment) {
104 struct {
105 std::string nextEnrollmentStr;
106 face::NextEnrollment nextEnrollment;
107 } testData[] = {
108 {"1:20:true", {1, {{20}}, true}},
109 {"1:50,60,70:true", {1, {{50}, {60}, {70}}, true}},
110 {"2:50-[21],60,70-[4,1002,1]:false",
111 {2,
112 {{50, {{AcquiredInfo::START}}},
113 {60},
114 {70, {{AcquiredInfo::TOO_DARK}, {1002}, {AcquiredInfo::GOOD}}}},
115 false}},
116 };
117
118 for (auto& d : testData) {
119 mVhal->setNextEnrollment(d.nextEnrollment);
120 ASSERT_TRUE(Face::cfg().get<std::string>("next_enrollment") == d.nextEnrollmentStr);
121 }
122 }
123
TEST_F(VirtualHalTest,authenticator_id_int64)124 TEST_F(VirtualHalTest, authenticator_id_int64) {
125 mVhal->setAuthenticatorId(12345678900);
126 ASSERT_TRUE(Face::cfg().get<int64_t>("authenticator_id") == 12345678900);
127 }
128
TEST_F(VirtualHalTest,opeationAuthenticateFails_bool)129 TEST_F(VirtualHalTest, opeationAuthenticateFails_bool) {
130 mVhal->setOperationAuthenticateFails(true);
131 ASSERT_TRUE(Face::cfg().get<bool>("operation_authenticate_fails"));
132 }
133
TEST_F(VirtualHalTest,operationAuthenticateAcquired_int32_vector)134 TEST_F(VirtualHalTest, operationAuthenticateAcquired_int32_vector) {
135 using Tag = AcquiredInfoAndVendorCode::Tag;
136 std::vector<AcquiredInfoAndVendorCode> ac{
137 {AcquiredInfo::START}, {AcquiredInfo::TOO_FAR}, {1023}};
138 mVhal->setOperationAuthenticateAcquired(ac);
139 OptIntVec ac_get = Face::cfg().getopt<OptIntVec>("operation_authenticate_acquired");
140 ASSERT_TRUE(ac_get.size() == ac.size());
141 for (int i = 0; i < ac.size(); i++) {
142 int acCode = (ac[i].getTag() == Tag::acquiredInfo) ? (int)ac[i].get<Tag::acquiredInfo>()
143 : ac[i].get<Tag::vendorCode>();
144 ASSERT_TRUE(acCode == ac_get[i]);
145 }
146 }
147
TEST_F(VirtualHalTest,type)148 TEST_F(VirtualHalTest, type) {
149 struct {
150 FaceSensorType type;
151 const char* typeStr;
152 } typeMap[] = {{FaceSensorType::RGB, "rgb"},
153 {FaceSensorType::IR, "ir"},
154 {FaceSensorType::UNKNOWN, "unknown"}};
155 for (auto const& x : typeMap) {
156 mVhal->setType(x.type);
157 ASSERT_TRUE(Face::cfg().get<std::string>("type") == x.typeStr);
158 }
159 }
160
TEST_F(VirtualHalTest,sensorStrength)161 TEST_F(VirtualHalTest, sensorStrength) {
162 struct {
163 common::SensorStrength strength;
164 const char* strengthStr;
165 } strengths[] = {{common::SensorStrength::CONVENIENCE, "CONVENIENCE"},
166 {common::SensorStrength::WEAK, "WEAK"},
167 {common::SensorStrength::STRONG, "STRONG"}};
168
169 for (auto const& x : strengths) {
170 mVhal->setSensorStrength(x.strength);
171 ASSERT_TRUE(Face::cfg().get<std::string>("strength") == x.strengthStr);
172 }
173 }
174
TEST_F(VirtualHalTest,setLatency)175 TEST_F(VirtualHalTest, setLatency) {
176 ndk::ScopedAStatus status;
177 std::vector<int32_t> in_lats[] = {{1}, {2, 3}, {5, 4}};
178 for (auto const& in_lat : in_lats) {
179 status = mVhal->setOperationAuthenticateLatency(in_lat);
180 ASSERT_TRUE(status.isOk());
181 OptIntVec out_lat = Face::cfg().getopt<OptIntVec>("operation_authenticate_latency");
182 ASSERT_TRUE(in_lat.size() == out_lat.size());
183 for (int i = 0; i < in_lat.size(); i++) {
184 ASSERT_TRUE(in_lat[i] == out_lat[i]);
185 }
186 }
187
188 std::vector<int32_t> bad_in_lats[] = {{}, {1, 2, 3}, {1, -3}};
189 for (auto const& in_lat : bad_in_lats) {
190 status = mVhal->setOperationAuthenticateLatency(in_lat);
191 ASSERT_TRUE(!status.isOk());
192 ASSERT_TRUE(status.getServiceSpecificError() == IVirtualHal::STATUS_INVALID_PARAMETER);
193 }
194 }
195
TEST_F(VirtualHalTest,setOperationAuthenticateDuration)196 TEST_F(VirtualHalTest, setOperationAuthenticateDuration) {
197 ndk::ScopedAStatus status = validateNonNegativeInputOfInt32(
198 "operation_authenticate_duration", &IVirtualHal::setOperationAuthenticateDuration,
199 {0, 33});
200 ASSERT_TRUE(status.isOk());
201 }
202
TEST_F(VirtualHalTest,setLockoutTimedDuration)203 TEST_F(VirtualHalTest, setLockoutTimedDuration) {
204 ndk::ScopedAStatus status = validateNonNegativeInputOfInt32(
205 "lockout_timed_duration", &IVirtualHal::setLockoutTimedDuration, {0, 35});
206 ASSERT_TRUE(status.isOk());
207 }
208
TEST_F(VirtualHalTest,setLockoutTimedThreshold)209 TEST_F(VirtualHalTest, setLockoutTimedThreshold) {
210 ndk::ScopedAStatus status = validateNonNegativeInputOfInt32(
211 "lockout_timed_threshold", &IVirtualHal::setLockoutTimedThreshold, {0, 36});
212 ASSERT_TRUE(status.isOk());
213 }
214
TEST_F(VirtualHalTest,setLockoutPermanentThreshold)215 TEST_F(VirtualHalTest, setLockoutPermanentThreshold) {
216 ndk::ScopedAStatus status = validateNonNegativeInputOfInt32(
217 "lockout_permanent_threshold", &IVirtualHal::setLockoutPermanentThreshold, {0, 37});
218 ASSERT_TRUE(status.isOk());
219 }
220
TEST_F(VirtualHalTest,setOthers)221 TEST_F(VirtualHalTest, setOthers) {
222 // Verify that there is no CHECK() failures
223 mVhal->setEnrollments({7, 6, 5});
224 mVhal->setChallenge(111222333444555666);
225 mVhal->setOperationAuthenticateError(4);
226 mVhal->setOperationEnrollLatency({4, 5});
227 mVhal->setLockout(false);
228 mVhal->setLockoutEnable(false);
229 }
230
231 } // namespace aidl::android::hardware::biometrics::face
232
main(int argc,char ** argv)233 int main(int argc, char** argv) {
234 testing::InitGoogleTest(&argc, argv);
235 ABinderProcess_startThreadPool();
236 return RUN_ALL_TESTS();
237 }
238