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 #include <aidl/Gtest.h>
18 #include <aidl/Vintf.h>
19 #include <aidl/android/hardware/biometrics/fingerprint/BnFingerprint.h>
20 #include <aidl/android/hardware/biometrics/fingerprint/BnSessionCallback.h>
21
22 #include <android/binder_manager.h>
23 #include <android/binder_process.h>
24
25 #include <chrono>
26 #include <future>
27
28 namespace aidl::android::hardware::biometrics::fingerprint {
29 namespace {
30
31 using namespace std::literals::chrono_literals;
32
33 constexpr int kSensorId = 0;
34 constexpr int kUserId = 0;
35
36 class SessionCallback : public BnSessionCallback {
37 public:
onChallengeGenerated(int64_t challenge)38 ndk::ScopedAStatus onChallengeGenerated(int64_t challenge) override {
39 auto lock = std::lock_guard{mMutex};
40 mOnChallengeGeneratedInvoked = true;
41 mGeneratedChallenge = challenge;
42 mCv.notify_one();
43 return ndk::ScopedAStatus::ok();
44 }
45
onChallengeRevoked(int64_t challenge)46 ndk::ScopedAStatus onChallengeRevoked(int64_t challenge) override {
47 auto lock = std::lock_guard{mMutex};
48 mOnChallengeRevokedInvoked = true;
49 mRevokedChallenge = challenge;
50 mCv.notify_one();
51 return ndk::ScopedAStatus::ok();
52 }
53
onAcquired(AcquiredInfo,int32_t)54 ndk::ScopedAStatus onAcquired(AcquiredInfo /*info*/, int32_t /*vendorCode*/) override {
55 return ndk::ScopedAStatus::ok();
56 }
57
onError(Error error,int32_t)58 ndk::ScopedAStatus onError(Error error, int32_t /*vendorCode*/) override {
59 auto lock = std::lock_guard{mMutex};
60 mError = error;
61 mOnErrorInvoked = true;
62 mCv.notify_one();
63 return ndk::ScopedAStatus::ok();
64 }
65
onEnrollmentProgress(int32_t,int32_t)66 ndk::ScopedAStatus onEnrollmentProgress(int32_t /*enrollmentId*/,
67 int32_t /*remaining*/) override {
68 return ndk::ScopedAStatus::ok();
69 }
70
onAuthenticationSucceeded(int32_t,const keymaster::HardwareAuthToken &)71 ndk::ScopedAStatus onAuthenticationSucceeded(
72 int32_t /*enrollmentId*/, const keymaster::HardwareAuthToken& /*hat*/) override {
73 return ndk::ScopedAStatus::ok();
74 }
75
onAuthenticationFailed()76 ndk::ScopedAStatus onAuthenticationFailed() override { return ndk::ScopedAStatus::ok(); }
77
onLockoutTimed(int64_t)78 ndk::ScopedAStatus onLockoutTimed(int64_t /*durationMillis*/) override {
79 return ndk::ScopedAStatus::ok();
80 }
81
onLockoutPermanent()82 ndk::ScopedAStatus onLockoutPermanent() override { return ndk::ScopedAStatus::ok(); }
83
onLockoutCleared()84 ndk::ScopedAStatus onLockoutCleared() override { return ndk::ScopedAStatus::ok(); }
85
onInteractionDetected()86 ndk::ScopedAStatus onInteractionDetected() override { return ndk::ScopedAStatus::ok(); }
87
onEnrollmentsEnumerated(const std::vector<int32_t> &)88 ndk::ScopedAStatus onEnrollmentsEnumerated(
89 const std::vector<int32_t>& /*enrollmentIds*/) override {
90 auto lock = std::lock_guard{mMutex};
91 mOnEnrollmentsEnumeratedInvoked = true;
92 mCv.notify_one();
93 return ndk::ScopedAStatus::ok();
94 }
95
onEnrollmentsRemoved(const std::vector<int32_t> &)96 ndk::ScopedAStatus onEnrollmentsRemoved(
97 const std::vector<int32_t>& /*enrollmentIds*/) override {
98 auto lock = std::lock_guard{mMutex};
99 mOnEnrollmentsRemovedInvoked = true;
100 mCv.notify_one();
101 return ndk::ScopedAStatus::ok();
102 }
103
onAuthenticatorIdRetrieved(int64_t)104 ndk::ScopedAStatus onAuthenticatorIdRetrieved(int64_t /*authenticatorId*/) override {
105 auto lock = std::lock_guard{mMutex};
106 mOnAuthenticatorIdRetrievedInvoked = true;
107 mCv.notify_one();
108 return ndk::ScopedAStatus::ok();
109 }
110
onAuthenticatorIdInvalidated(int64_t)111 ndk::ScopedAStatus onAuthenticatorIdInvalidated(int64_t /*newAuthenticatorId*/) override {
112 auto lock = std::lock_guard{mMutex};
113 mOnAuthenticatorIdInvalidatedInvoked = true;
114 mCv.notify_one();
115 return ndk::ScopedAStatus::ok();
116 }
117
onSessionClosed()118 ndk::ScopedAStatus onSessionClosed() override {
119 auto lock = std::lock_guard{mMutex};
120 mOnSessionClosedInvoked = true;
121 mCv.notify_one();
122 return ndk::ScopedAStatus::ok();
123 }
124
125 std::mutex mMutex;
126 std::condition_variable mCv;
127 Error mError = Error::UNKNOWN;
128 int64_t mGeneratedChallenge = 0;
129 int64_t mRevokedChallenge = 0;
130 bool mOnChallengeGeneratedInvoked = false;
131 bool mOnChallengeRevokedInvoked = false;
132 bool mOnErrorInvoked = false;
133 bool mOnEnrollmentsEnumeratedInvoked = false;
134 bool mOnEnrollmentsRemovedInvoked = false;
135 bool mOnAuthenticatorIdRetrievedInvoked = false;
136 bool mOnAuthenticatorIdInvalidatedInvoked = false;
137 bool mOnSessionClosedInvoked = false;
138 };
139
140 class Fingerprint : public testing::TestWithParam<std::string> {
141 protected:
SetUp()142 void SetUp() override {
143 // Prepare the callback.
144 mCb = ndk::SharedRefBase::make<SessionCallback>();
145
146 int retries = 0;
147 bool isOk = false;
148 // If the first attempt to create a session fails, we try to create a session again. The
149 // first attempt might fail if the framework already has an active session. The AIDL
150 // contract doesn't allow to create a new session without closing the old one. However, we
151 // can't close the framework's session from VTS. The expectation here is that the HAL will
152 // crash after the first illegal attempt to create a session, then it will restart, and then
153 // we'll be able to create a session.
154 do {
155 // Get an instance of the HAL.
156 AIBinder* binder = AServiceManager_waitForService(GetParam().c_str());
157 ASSERT_NE(binder, nullptr);
158 mHal = IFingerprint::fromBinder(ndk::SpAIBinder(binder));
159
160 // Create a session.
161 isOk = mHal->createSession(kSensorId, kUserId, mCb, &mSession).isOk();
162 ++retries;
163 } while (!isOk && retries < 2);
164
165 ASSERT_TRUE(isOk);
166 }
167
TearDown()168 void TearDown() override {
169 // Close the mSession.
170 ASSERT_TRUE(mSession->close().isOk());
171
172 // Make sure the mSession is closed.
173 auto lock = std::unique_lock<std::mutex>(mCb->mMutex);
174 mCb->mCv.wait(lock, [this] { return mCb->mOnSessionClosedInvoked; });
175 }
176
177 std::shared_ptr<IFingerprint> mHal;
178 std::shared_ptr<SessionCallback> mCb;
179 std::shared_ptr<ISession> mSession;
180 };
181
TEST_P(Fingerprint,GetSensorPropsWorksTest)182 TEST_P(Fingerprint, GetSensorPropsWorksTest) {
183 std::vector<SensorProps> sensorProps;
184
185 // Call the method.
186 ASSERT_TRUE(mHal->getSensorProps(&sensorProps).isOk());
187
188 // Make sure the sensorProps aren't empty.
189 ASSERT_FALSE(sensorProps.empty());
190 ASSERT_FALSE(sensorProps[0].commonProps.componentInfo.empty());
191 }
192
TEST_P(Fingerprint,EnrollWithBadHatResultsInErrorTest)193 TEST_P(Fingerprint, EnrollWithBadHatResultsInErrorTest) {
194 // Call the method.
195 auto hat = keymaster::HardwareAuthToken{};
196 std::shared_ptr<common::ICancellationSignal> cancellationSignal;
197 ASSERT_TRUE(mSession->enroll(hat, &cancellationSignal).isOk());
198
199 // Make sure an error is returned.
200 auto lock = std::unique_lock{mCb->mMutex};
201 mCb->mCv.wait(lock, [this] { return mCb->mOnErrorInvoked; });
202 }
203
TEST_P(Fingerprint,GenerateChallengeProducesUniqueChallengesTest)204 TEST_P(Fingerprint, GenerateChallengeProducesUniqueChallengesTest) {
205 static constexpr int kIterations = 100;
206
207 auto challenges = std::set<int>{};
208 for (unsigned int i = 0; i < kIterations; ++i) {
209 // Call the method.
210 ASSERT_TRUE(mSession->generateChallenge().isOk());
211
212 // Check that the generated challenge is unique and not 0.
213 auto lock = std::unique_lock{mCb->mMutex};
214 mCb->mCv.wait(lock, [this] { return mCb->mOnChallengeGeneratedInvoked; });
215 ASSERT_NE(mCb->mGeneratedChallenge, 0);
216 ASSERT_EQ(challenges.find(mCb->mGeneratedChallenge), challenges.end());
217
218 challenges.insert(mCb->mGeneratedChallenge);
219 mCb->mOnChallengeGeneratedInvoked = false;
220 }
221 }
222
TEST_P(Fingerprint,RevokeChallengeWorksForNonexistentChallengeTest)223 TEST_P(Fingerprint, RevokeChallengeWorksForNonexistentChallengeTest) {
224 const int64_t nonexistentChallenge = 123;
225
226 // Call the method.
227 ASSERT_TRUE(mSession->revokeChallenge(nonexistentChallenge).isOk());
228
229 // Check that the challenge is revoked and matches the requested challenge.
230 auto lock = std::unique_lock{mCb->mMutex};
231 mCb->mCv.wait(lock, [this] { return mCb->mOnChallengeRevokedInvoked; });
232 ASSERT_EQ(mCb->mRevokedChallenge, nonexistentChallenge);
233 }
234
TEST_P(Fingerprint,RevokeChallengeWorksForExistentChallengeTest)235 TEST_P(Fingerprint, RevokeChallengeWorksForExistentChallengeTest) {
236 // Generate a challenge.
237 ASSERT_TRUE(mSession->generateChallenge().isOk());
238
239 // Wait for the result.
240 auto lock = std::unique_lock{mCb->mMutex};
241 mCb->mCv.wait(lock, [this] { return mCb->mOnChallengeGeneratedInvoked; });
242 lock.unlock();
243
244 // Revoke the challenge.
245 ASSERT_TRUE(mSession->revokeChallenge(mCb->mGeneratedChallenge).isOk());
246
247 // Check that the challenge is revoked and matches the requested challenge.
248 lock.lock();
249 mCb->mCv.wait(lock, [this] { return mCb->mOnChallengeRevokedInvoked; });
250 ASSERT_EQ(mCb->mRevokedChallenge, mCb->mGeneratedChallenge);
251 }
252
TEST_P(Fingerprint,EnumerateEnrollmentsWorksTest)253 TEST_P(Fingerprint, EnumerateEnrollmentsWorksTest) {
254 // Call the method.
255 ASSERT_TRUE(mSession->enumerateEnrollments().isOk());
256
257 // Wait for the result.
258 auto lock = std::unique_lock{mCb->mMutex};
259 mCb->mCv.wait(lock, [this] { return mCb->mOnEnrollmentsEnumeratedInvoked; });
260 }
261
TEST_P(Fingerprint,RemoveEnrollmentsWorksTest)262 TEST_P(Fingerprint, RemoveEnrollmentsWorksTest) {
263 // Call the method.
264 ASSERT_TRUE(mSession->removeEnrollments({}).isOk());
265
266 // Wait for the result.
267 auto lock = std::unique_lock{mCb->mMutex};
268 mCb->mCv.wait(lock, [this] { return mCb->mOnEnrollmentsRemovedInvoked; });
269 }
270
TEST_P(Fingerprint,GetAuthenticatorIdWorksTest)271 TEST_P(Fingerprint, GetAuthenticatorIdWorksTest) {
272 // Call the method.
273 ASSERT_TRUE(mSession->getAuthenticatorId().isOk());
274
275 // Wait for the result.
276 auto lock = std::unique_lock{mCb->mMutex};
277 mCb->mCv.wait(lock, [this] { return mCb->mOnAuthenticatorIdRetrievedInvoked; });
278 }
279
TEST_P(Fingerprint,InvalidateAuthenticatorIdWorksTest)280 TEST_P(Fingerprint, InvalidateAuthenticatorIdWorksTest) {
281 // Call the method.
282 ASSERT_TRUE(mSession->invalidateAuthenticatorId().isOk());
283
284 // Wait for the result.
285 auto lock = std::unique_lock{mCb->mMutex};
286 mCb->mCv.wait(lock, [this] { return mCb->mOnAuthenticatorIdInvalidatedInvoked; });
287 }
288
289 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(Fingerprint);
290 INSTANTIATE_TEST_SUITE_P(
291 IFingerprint, Fingerprint,
292 testing::ValuesIn(::android::getAidlHalInstanceNames(IFingerprint::descriptor)),
293 ::android::PrintInstanceNameToString);
294
295 } // namespace
296 } // namespace aidl::android::hardware::biometrics::fingerprint
297
main(int argc,char ** argv)298 int main(int argc, char** argv) {
299 ::testing::InitGoogleTest(&argc, argv);
300 ABinderProcess_setThreadPoolMaxThreadCount(1);
301 ABinderProcess_startThreadPool();
302 return RUN_ALL_TESTS();
303 }
304