blob: 261ae20bd270b9c49cc3b54b3bc54fb90bd454e2 [file] [log] [blame]
Ilya Matyukhin14412df2020-08-27 14:26:06 -07001/*
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 */
Ilya Matyukhin5e09b822021-02-26 12:24:18 -080016
Ilya Matyukhin14412df2020-08-27 14:26:06 -070017#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
Ilya Matyukhincaa67672021-03-23 19:00:36 -070025#include <chrono>
Ilya Matyukhin14412df2020-08-27 14:26:06 -070026#include <future>
27
28namespace aidl::android::hardware::biometrics::fingerprint {
29namespace {
30
Ilya Matyukhincaa67672021-03-23 19:00:36 -070031using namespace std::literals::chrono_literals;
32
Ilya Matyukhin14412df2020-08-27 14:26:06 -070033constexpr int kSensorId = 0;
34constexpr int kUserId = 0;
Ilya Matyukhin14412df2020-08-27 14:26:06 -070035
36class SessionCallback : public BnSessionCallback {
37 public:
Ilya Matyukhin04247242021-07-02 20:34:52 +000038 ndk::ScopedAStatus onChallengeGenerated(int64_t challenge) override {
39 auto lock = std::lock_guard{mMutex};
40 mOnChallengeGeneratedInvoked = true;
41 mGeneratedChallenge = challenge;
42 mCv.notify_one();
Ilya Matyukhin3d54f452020-10-15 17:32:09 -070043 return ndk::ScopedAStatus::ok();
44 }
45
Ilya Matyukhin04247242021-07-02 20:34:52 +000046 ndk::ScopedAStatus onChallengeRevoked(int64_t challenge) override {
47 auto lock = std::lock_guard{mMutex};
48 mOnChallengeRevokedInvoked = true;
49 mRevokedChallenge = challenge;
50 mCv.notify_one();
Ilya Matyukhin3d54f452020-10-15 17:32:09 -070051 return ndk::ScopedAStatus::ok();
52 }
53
Ilya Matyukhin14412df2020-08-27 14:26:06 -070054 ndk::ScopedAStatus onAcquired(AcquiredInfo /*info*/, int32_t /*vendorCode*/) override {
55 return ndk::ScopedAStatus::ok();
56 }
57
Ilya Matyukhin04247242021-07-02 20:34:52 +000058 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();
Ilya Matyukhin14412df2020-08-27 14:26:06 -070063 return ndk::ScopedAStatus::ok();
64 }
65
Kevin Chyn1288c102020-09-18 16:42:44 -070066 ndk::ScopedAStatus onEnrollmentProgress(int32_t /*enrollmentId*/,
67 int32_t /*remaining*/) override {
Ilya Matyukhin14412df2020-08-27 14:26:06 -070068 return ndk::ScopedAStatus::ok();
69 }
70
Ilya Matyukhin5e09b822021-02-26 12:24:18 -080071 ndk::ScopedAStatus onAuthenticationSucceeded(
72 int32_t /*enrollmentId*/, const keymaster::HardwareAuthToken& /*hat*/) override {
Ilya Matyukhin14412df2020-08-27 14:26:06 -070073 return ndk::ScopedAStatus::ok();
74 }
75
Ilya Matyukhin5e09b822021-02-26 12:24:18 -080076 ndk::ScopedAStatus onAuthenticationFailed() override { return ndk::ScopedAStatus::ok(); }
Kevin Chyn64c13a02020-09-21 12:37:56 -070077
Kevin Chynef79d662020-09-22 12:14:44 -070078 ndk::ScopedAStatus onLockoutTimed(int64_t /*durationMillis*/) override {
79 return ndk::ScopedAStatus::ok();
80 }
81
Ilya Matyukhin5e09b822021-02-26 12:24:18 -080082 ndk::ScopedAStatus onLockoutPermanent() override { return ndk::ScopedAStatus::ok(); }
Kevin Chynef79d662020-09-22 12:14:44 -070083
Ilya Matyukhin5e09b822021-02-26 12:24:18 -080084 ndk::ScopedAStatus onLockoutCleared() override { return ndk::ScopedAStatus::ok(); }
Kevin Chynef79d662020-09-22 12:14:44 -070085
Ilya Matyukhin14412df2020-08-27 14:26:06 -070086 ndk::ScopedAStatus onInteractionDetected() override { return ndk::ScopedAStatus::ok(); }
87
88 ndk::ScopedAStatus onEnrollmentsEnumerated(
89 const std::vector<int32_t>& /*enrollmentIds*/) override {
Ilya Matyukhin04247242021-07-02 20:34:52 +000090 auto lock = std::lock_guard{mMutex};
91 mOnEnrollmentsEnumeratedInvoked = true;
92 mCv.notify_one();
Ilya Matyukhin14412df2020-08-27 14:26:06 -070093 return ndk::ScopedAStatus::ok();
94 }
95
96 ndk::ScopedAStatus onEnrollmentsRemoved(
97 const std::vector<int32_t>& /*enrollmentIds*/) override {
Ilya Matyukhin04247242021-07-02 20:34:52 +000098 auto lock = std::lock_guard{mMutex};
99 mOnEnrollmentsRemovedInvoked = true;
100 mCv.notify_one();
Ilya Matyukhin14412df2020-08-27 14:26:06 -0700101 return ndk::ScopedAStatus::ok();
102 }
103
Kevin Chyn6e862c32020-09-16 18:27:37 -0700104 ndk::ScopedAStatus onAuthenticatorIdRetrieved(int64_t /*authenticatorId*/) override {
Ilya Matyukhin04247242021-07-02 20:34:52 +0000105 auto lock = std::lock_guard{mMutex};
106 mOnAuthenticatorIdRetrievedInvoked = true;
107 mCv.notify_one();
Kevin Chyn6e862c32020-09-16 18:27:37 -0700108 return ndk::ScopedAStatus::ok();
109 }
110
Kevin Chynf7890cc2021-01-11 17:08:36 -0800111 ndk::ScopedAStatus onAuthenticatorIdInvalidated(int64_t /*newAuthenticatorId*/) override {
Ilya Matyukhin04247242021-07-02 20:34:52 +0000112 auto lock = std::lock_guard{mMutex};
113 mOnAuthenticatorIdInvalidatedInvoked = true;
114 mCv.notify_one();
Kevin Chyn6e862c32020-09-16 18:27:37 -0700115 return ndk::ScopedAStatus::ok();
116 }
117
Ilya Matyukhincaa67672021-03-23 19:00:36 -0700118 ndk::ScopedAStatus onSessionClosed() override {
Ilya Matyukhin04247242021-07-02 20:34:52 +0000119 auto lock = std::lock_guard{mMutex};
120 mOnSessionClosedInvoked = true;
121 mCv.notify_one();
Ilya Matyukhincaa67672021-03-23 19:00:36 -0700122 return ndk::ScopedAStatus::ok();
123 }
Ilya Matyukhincbbfa932021-03-22 13:25:15 -0700124
Ilya Matyukhin04247242021-07-02 20:34:52 +0000125 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;
Ilya Matyukhin14412df2020-08-27 14:26:06 -0700138};
139
140class Fingerprint : public testing::TestWithParam<std::string> {
Jeff Pu8c5bb252025-02-06 15:12:13 +0000141 static void HalServiceDied(void* cookie) {
142 auto halDeathPromise = static_cast<std::promise<void>*>(cookie);
143 halDeathPromise->set_value();
144 }
145
Ilya Matyukhin14412df2020-08-27 14:26:06 -0700146 protected:
147 void SetUp() override {
Ilya Matyukhin04247242021-07-02 20:34:52 +0000148 // Prepare the callback.
149 mCb = ndk::SharedRefBase::make<SessionCallback>();
150
151 int retries = 0;
152 bool isOk = false;
153 // If the first attempt to create a session fails, we try to create a session again. The
154 // first attempt might fail if the framework already has an active session. The AIDL
155 // contract doesn't allow to create a new session without closing the old one. However, we
156 // can't close the framework's session from VTS. The expectation here is that the HAL will
157 // crash after the first illegal attempt to create a session, then it will restart, and then
158 // we'll be able to create a session.
159 do {
160 // Get an instance of the HAL.
161 AIBinder* binder = AServiceManager_waitForService(GetParam().c_str());
162 ASSERT_NE(binder, nullptr);
163 mHal = IFingerprint::fromBinder(ndk::SpAIBinder(binder));
164
Jeff Pu8c5bb252025-02-06 15:12:13 +0000165 // Create HAL service death notifier
166 auto halDeathPromise = std::make_shared<std::promise<void>>();
167 mHalDeathRecipient = ndk::ScopedAIBinder_DeathRecipient(
168 AIBinder_DeathRecipient_new(&HalServiceDied));
169 ASSERT_EQ(STATUS_OK, AIBinder_linkToDeath(binder, mHalDeathRecipient.get(),
170 static_cast<void*>(halDeathPromise.get())));
171
Ilya Matyukhin04247242021-07-02 20:34:52 +0000172 // Create a session.
173 isOk = mHal->createSession(kSensorId, kUserId, mCb, &mSession).isOk();
Jeff Pu8c5bb252025-02-06 15:12:13 +0000174
175 if (!isOk) {
176 // Failed to create session on first attempt, it is likely that the HAL service
177 // is dying or dead. Wait for its death notification signal before next try
178 auto future = halDeathPromise->get_future();
179 auto status = future.wait_for(std::chrono::milliseconds(500));
180 EXPECT_EQ(status, std::future_status::ready);
181 }
182
Ilya Matyukhin04247242021-07-02 20:34:52 +0000183 ++retries;
184 } while (!isOk && retries < 2);
185
186 ASSERT_TRUE(isOk);
187 }
188
189 void TearDown() override {
190 // Close the mSession.
191 ASSERT_TRUE(mSession->close().isOk());
192
193 // Make sure the mSession is closed.
194 auto lock = std::unique_lock<std::mutex>(mCb->mMutex);
195 mCb->mCv.wait(lock, [this] { return mCb->mOnSessionClosedInvoked; });
Ilya Matyukhin14412df2020-08-27 14:26:06 -0700196 }
197
Ilya Matyukhin5e09b822021-02-26 12:24:18 -0800198 std::shared_ptr<IFingerprint> mHal;
Ilya Matyukhin04247242021-07-02 20:34:52 +0000199 std::shared_ptr<SessionCallback> mCb;
200 std::shared_ptr<ISession> mSession;
Jeff Pu8c5bb252025-02-06 15:12:13 +0000201 ::ndk::ScopedAIBinder_DeathRecipient mHalDeathRecipient;
Ilya Matyukhin14412df2020-08-27 14:26:06 -0700202};
203
Ilya Matyukhin04247242021-07-02 20:34:52 +0000204TEST_P(Fingerprint, GetSensorPropsWorksTest) {
205 std::vector<SensorProps> sensorProps;
Ilya Matyukhin14412df2020-08-27 14:26:06 -0700206
Ilya Matyukhin04247242021-07-02 20:34:52 +0000207 // Call the method.
208 ASSERT_TRUE(mHal->getSensorProps(&sensorProps).isOk());
Ilya Matyukhin14412df2020-08-27 14:26:06 -0700209
Ilya Matyukhin04247242021-07-02 20:34:52 +0000210 // Make sure the sensorProps aren't empty.
211 ASSERT_FALSE(sensorProps.empty());
212 ASSERT_FALSE(sensorProps[0].commonProps.componentInfo.empty());
213}
214
215TEST_P(Fingerprint, EnrollWithBadHatResultsInErrorTest) {
216 // Call the method.
217 auto hat = keymaster::HardwareAuthToken{};
Ilya Matyukhin5e09b822021-02-26 12:24:18 -0800218 std::shared_ptr<common::ICancellationSignal> cancellationSignal;
Ilya Matyukhin04247242021-07-02 20:34:52 +0000219 ASSERT_TRUE(mSession->enroll(hat, &cancellationSignal).isOk());
Ilya Matyukhin14412df2020-08-27 14:26:06 -0700220
Ilya Matyukhin04247242021-07-02 20:34:52 +0000221 // Make sure an error is returned.
222 auto lock = std::unique_lock{mCb->mMutex};
223 mCb->mCv.wait(lock, [this] { return mCb->mOnErrorInvoked; });
224}
Ilya Matyukhin5e09b822021-02-26 12:24:18 -0800225
Ilya Matyukhin04247242021-07-02 20:34:52 +0000226TEST_P(Fingerprint, GenerateChallengeProducesUniqueChallengesTest) {
227 static constexpr int kIterations = 100;
228
229 auto challenges = std::set<int>{};
230 for (unsigned int i = 0; i < kIterations; ++i) {
231 // Call the method.
232 ASSERT_TRUE(mSession->generateChallenge().isOk());
233
234 // Check that the generated challenge is unique and not 0.
235 auto lock = std::unique_lock{mCb->mMutex};
236 mCb->mCv.wait(lock, [this] { return mCb->mOnChallengeGeneratedInvoked; });
237 ASSERT_NE(mCb->mGeneratedChallenge, 0);
238 ASSERT_EQ(challenges.find(mCb->mGeneratedChallenge), challenges.end());
239
240 challenges.insert(mCb->mGeneratedChallenge);
241 mCb->mOnChallengeGeneratedInvoked = false;
242 }
243}
244
245TEST_P(Fingerprint, RevokeChallengeWorksForNonexistentChallengeTest) {
246 const int64_t nonexistentChallenge = 123;
247
248 // Call the method.
249 ASSERT_TRUE(mSession->revokeChallenge(nonexistentChallenge).isOk());
250
251 // Check that the challenge is revoked and matches the requested challenge.
252 auto lock = std::unique_lock{mCb->mMutex};
253 mCb->mCv.wait(lock, [this] { return mCb->mOnChallengeRevokedInvoked; });
254 ASSERT_EQ(mCb->mRevokedChallenge, nonexistentChallenge);
255}
256
257TEST_P(Fingerprint, RevokeChallengeWorksForExistentChallengeTest) {
258 // Generate a challenge.
259 ASSERT_TRUE(mSession->generateChallenge().isOk());
260
261 // Wait for the result.
262 auto lock = std::unique_lock{mCb->mMutex};
263 mCb->mCv.wait(lock, [this] { return mCb->mOnChallengeGeneratedInvoked; });
264 lock.unlock();
265
266 // Revoke the challenge.
267 ASSERT_TRUE(mSession->revokeChallenge(mCb->mGeneratedChallenge).isOk());
268
269 // Check that the challenge is revoked and matches the requested challenge.
270 lock.lock();
271 mCb->mCv.wait(lock, [this] { return mCb->mOnChallengeRevokedInvoked; });
272 ASSERT_EQ(mCb->mRevokedChallenge, mCb->mGeneratedChallenge);
273}
274
275TEST_P(Fingerprint, EnumerateEnrollmentsWorksTest) {
276 // Call the method.
277 ASSERT_TRUE(mSession->enumerateEnrollments().isOk());
278
279 // Wait for the result.
280 auto lock = std::unique_lock{mCb->mMutex};
281 mCb->mCv.wait(lock, [this] { return mCb->mOnEnrollmentsEnumeratedInvoked; });
282}
283
284TEST_P(Fingerprint, RemoveEnrollmentsWorksTest) {
285 // Call the method.
286 ASSERT_TRUE(mSession->removeEnrollments({}).isOk());
287
288 // Wait for the result.
289 auto lock = std::unique_lock{mCb->mMutex};
290 mCb->mCv.wait(lock, [this] { return mCb->mOnEnrollmentsRemovedInvoked; });
291}
292
293TEST_P(Fingerprint, GetAuthenticatorIdWorksTest) {
294 // Call the method.
295 ASSERT_TRUE(mSession->getAuthenticatorId().isOk());
296
297 // Wait for the result.
298 auto lock = std::unique_lock{mCb->mMutex};
299 mCb->mCv.wait(lock, [this] { return mCb->mOnAuthenticatorIdRetrievedInvoked; });
300}
301
302TEST_P(Fingerprint, InvalidateAuthenticatorIdWorksTest) {
303 // Call the method.
304 ASSERT_TRUE(mSession->invalidateAuthenticatorId().isOk());
305
306 // Wait for the result.
307 auto lock = std::unique_lock{mCb->mMutex};
308 mCb->mCv.wait(lock, [this] { return mCb->mOnAuthenticatorIdInvalidatedInvoked; });
Ilya Matyukhin14412df2020-08-27 14:26:06 -0700309}
310
311GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(Fingerprint);
312INSTANTIATE_TEST_SUITE_P(
313 IFingerprint, Fingerprint,
314 testing::ValuesIn(::android::getAidlHalInstanceNames(IFingerprint::descriptor)),
315 ::android::PrintInstanceNameToString);
316
317} // namespace
Ilya Matyukhin5e09b822021-02-26 12:24:18 -0800318} // namespace aidl::android::hardware::biometrics::fingerprint
Ilya Matyukhin14412df2020-08-27 14:26:06 -0700319
320int main(int argc, char** argv) {
321 ::testing::InitGoogleTest(&argc, argv);
322 ABinderProcess_setThreadPoolMaxThreadCount(1);
323 ABinderProcess_startThreadPool();
324 return RUN_ALL_TESTS();
325}