diff --git a/biometrics/fingerprint/aidl/default/Android.bp b/biometrics/fingerprint/aidl/default/Android.bp index fe224c9885..16302eb9af 100644 --- a/biometrics/fingerprint/aidl/default/Android.bp +++ b/biometrics/fingerprint/aidl/default/Android.bp @@ -110,6 +110,32 @@ cc_test { require_root: true, } +cc_test { + name: "android.hardware.biometrics.fingerprint.SessionTest", + local_include_dirs: ["include"], + srcs: [ + "tests/SessionTest.cpp", + "Session.cpp", + "FakeFingerprintEngine.cpp", + "FakeLockoutTracker.cpp", + ], + shared_libs: [ + "libbase", + "libbinder_ndk", + "android.hardware.biometrics.common.thread", + ], + static_libs: [ + "libandroid.hardware.biometrics.fingerprint.VirtualProps", + "android.hardware.biometrics.fingerprint-V3-ndk", + "android.hardware.biometrics.common-V3-ndk", + "android.hardware.keymaster-V4-ndk", + "android.hardware.biometrics.common.util", + ], + vendor: true, + test_suites: ["general-tests"], + require_root: true, +} + sysprop_library { name: "android.hardware.biometrics.fingerprint.VirtualProps", srcs: ["fingerprint.sysprop"], diff --git a/biometrics/fingerprint/aidl/default/Fingerprint.cpp b/biometrics/fingerprint/aidl/default/Fingerprint.cpp index 7808a13d16..f00a49d26e 100644 --- a/biometrics/fingerprint/aidl/default/Fingerprint.cpp +++ b/biometrics/fingerprint/aidl/default/Fingerprint.cpp @@ -103,6 +103,8 @@ ndk::ScopedAStatus Fingerprint::createSession(int32_t sensorId, int32_t userId, mSession = SharedRefBase::make(sensorId, userId, cb, mEngine.get(), &mWorker); *out = mSession; + mSession->linkToDeath(cb->asBinder().get()); + LOG(INFO) << "createSession: sensorId:" << sensorId << " userId:" << userId; return ndk::ScopedAStatus::ok(); } diff --git a/biometrics/fingerprint/aidl/default/Session.cpp b/biometrics/fingerprint/aidl/default/Session.cpp index 38d6a134e2..c06c9317e8 100644 --- a/biometrics/fingerprint/aidl/default/Session.cpp +++ b/biometrics/fingerprint/aidl/default/Session.cpp @@ -25,6 +25,14 @@ namespace aidl::android::hardware::biometrics::fingerprint { +void onClientDeath(void* cookie) { + LOG(INFO) << "FingerprintService has died"; + Session* session = static_cast(cookie); + if (session && !session->isClosed()) { + session->close(); + } +} + Session::Session(int sensorId, int userId, std::shared_ptr cb, FakeFingerprintEngine* engine, WorkerThread* worker) : mSensorId(sensorId), @@ -39,6 +47,12 @@ Session::Session(int sensorId, int userId, std::shared_ptr cb, CHECK(mEngine); CHECK(mWorker); CHECK(mCb); + + mDeathRecipient = AIBinder_DeathRecipient_new(onClientDeath); +} + +binder_status_t Session::linkToDeath(AIBinder* binder) { + return AIBinder_linkToDeath(binder, mDeathRecipient, this); } void Session::scheduleStateOrCrash(SessionState state) { @@ -228,6 +242,7 @@ ndk::ScopedAStatus Session::close() { // Crashing."; mCurrentState = SessionState::CLOSED; mCb->onSessionClosed(); + AIBinder_DeathRecipient_delete(mDeathRecipient); return ndk::ScopedAStatus::ok(); } diff --git a/biometrics/fingerprint/aidl/default/include/Session.h b/biometrics/fingerprint/aidl/default/include/Session.h index b596d9e2a9..526d5797cc 100644 --- a/biometrics/fingerprint/aidl/default/include/Session.h +++ b/biometrics/fingerprint/aidl/default/include/Session.h @@ -42,6 +42,8 @@ enum class SessionState { RESETTING_LOCKOUT, }; +void onClientDeath(void* cookie); + class Session : public BnSession { public: Session(int sensorId, int userId, std::shared_ptr cb, @@ -101,6 +103,8 @@ class Session : public BnSession { ndk::ScopedAStatus setIgnoreDisplayTouches(bool shouldIgnore) override; + binder_status_t linkToDeath(AIBinder* binder); + bool isClosed(); private: @@ -139,6 +143,9 @@ class Session : public BnSession { // modified from both the main and the worker threads. std::atomic mScheduledState; std::atomic mCurrentState; + + // Binder death handler. + AIBinder_DeathRecipient* mDeathRecipient; }; } // namespace aidl::android::hardware::biometrics::fingerprint diff --git a/biometrics/fingerprint/aidl/default/tests/SessionTest.cpp b/biometrics/fingerprint/aidl/default/tests/SessionTest.cpp new file mode 100644 index 0000000000..3b96d7f099 --- /dev/null +++ b/biometrics/fingerprint/aidl/default/tests/SessionTest.cpp @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include + +#include + +#include "Session.h" +#include "thread/WorkerThread.h" +#include "util/Util.h" + +using namespace ::android::fingerprint::virt; +using namespace ::aidl::android::hardware::biometrics::fingerprint; + +namespace aidl::android::hardware::biometrics::fingerprint { + +class TestSessionCallback : public BnSessionCallback { + public: + ndk::ScopedAStatus onChallengeGenerated(int64_t /*challenge*/) override { + return ndk::ScopedAStatus::ok(); + }; + ::ndk::ScopedAStatus onChallengeRevoked(int64_t /*challenge*/) override { + return ndk::ScopedAStatus::ok(); + }; + ::ndk::ScopedAStatus onError(fingerprint::Error /*error*/, int32_t /*vendorCode*/) override { + return ndk::ScopedAStatus::ok(); + }; + ::ndk::ScopedAStatus onEnrollmentProgress(int32_t /*enrollmentId*/, + int32_t /*remaining*/) override { + return ndk::ScopedAStatus::ok(); + }; + + ::ndk::ScopedAStatus onAuthenticationSucceeded(int32_t /*enrollmentId*/, + const keymaster::HardwareAuthToken&) override { + return ndk::ScopedAStatus::ok(); + }; + ::ndk::ScopedAStatus onAuthenticationFailed() override { return ndk::ScopedAStatus::ok(); }; + ::ndk::ScopedAStatus onInteractionDetected() override { return ndk::ScopedAStatus::ok(); }; + ndk::ScopedAStatus onAcquired(AcquiredInfo /*info*/, int32_t /*vendorCode*/) override { + return ndk::ScopedAStatus::ok(); + } + ::ndk::ScopedAStatus onEnrollmentsEnumerated( + const std::vector& /*enrollmentIds*/) override { + return ndk::ScopedAStatus::ok(); + }; + ::ndk::ScopedAStatus onEnrollmentsRemoved( + const std::vector& /*enrollmentIds*/) override { + return ndk::ScopedAStatus::ok(); + }; + ::ndk::ScopedAStatus onAuthenticatorIdRetrieved(int64_t /*authenticatorId*/) override { + return ndk::ScopedAStatus::ok(); + }; + ::ndk::ScopedAStatus onAuthenticatorIdInvalidated(int64_t /*authenticatorId*/) override { + return ndk::ScopedAStatus::ok(); + }; + ::ndk::ScopedAStatus onLockoutPermanent() override { return ndk::ScopedAStatus::ok(); }; + ndk::ScopedAStatus onLockoutTimed(int64_t /* timeout */) override { + return ndk::ScopedAStatus::ok(); + } + ndk::ScopedAStatus onLockoutCleared() override { return ndk::ScopedAStatus::ok(); } + ndk::ScopedAStatus onSessionClosed() override { + mIsClosed = true; + return ndk::ScopedAStatus::ok(); + } + + bool mIsClosed = false; +}; + +class SessionTest : public ::testing::Test { + public: + SessionTest() : mWorker(2) {} + + protected: + void SetUp() override { + mCb = ndk::SharedRefBase::make(); + mSession = ndk::SharedRefBase::make(1, 2, mCb, &mFakeFingerprintEngine, &mWorker); + ASSERT_TRUE(mSession != nullptr); + mSession->linkToDeath(mCb->asBinder().get()); + } + + void TearDown() override {} + + std::shared_ptr mSession; + std::shared_ptr mCb; + + private: + FakeFingerprintEngine mFakeFingerprintEngine; + WorkerThread mWorker; +}; + +TEST_F(SessionTest, close) { + ASSERT_TRUE(!mSession->isClosed()); + ASSERT_TRUE(!mCb->mIsClosed); + onClientDeath(nullptr); + ASSERT_TRUE(!mSession->isClosed()); + ASSERT_TRUE(!mCb->mIsClosed); + onClientDeath(static_cast(mSession.get())); + ASSERT_TRUE(mSession->isClosed()); + ASSERT_TRUE(mCb->mIsClosed); +} + +} // namespace aidl::android::hardware::biometrics::fingerprint + +int main(int argc, char** argv) { + testing::InitGoogleTest(&argc, argv); + ABinderProcess_startThreadPool(); + return RUN_ALL_TESTS(); +}