Close the session if Fingerprint servers die

by registering the death notification of the associated binder.
Bug: 273807765
Test: adb shell stop;adb shell start

Change-Id: Ifc60e68fdbf986a355f828a7fc11f2aecee4cbea
diff --git a/biometrics/fingerprint/aidl/default/Android.bp b/biometrics/fingerprint/aidl/default/Android.bp
index fe224c9..16302eb 100644
--- a/biometrics/fingerprint/aidl/default/Android.bp
+++ b/biometrics/fingerprint/aidl/default/Android.bp
@@ -110,6 +110,32 @@
     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 7808a13..f00a49d 100644
--- a/biometrics/fingerprint/aidl/default/Fingerprint.cpp
+++ b/biometrics/fingerprint/aidl/default/Fingerprint.cpp
@@ -103,6 +103,8 @@
     mSession = SharedRefBase::make<Session>(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 38d6a13..c06c931 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<Session*>(cookie);
+    if (session && !session->isClosed()) {
+        session->close();
+    }
+}
+
 Session::Session(int sensorId, int userId, std::shared_ptr<ISessionCallback> cb,
                  FakeFingerprintEngine* engine, WorkerThread* worker)
     : mSensorId(sensorId),
@@ -39,6 +47,12 @@
     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 @@
     // 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 b596d9e..526d579 100644
--- a/biometrics/fingerprint/aidl/default/include/Session.h
+++ b/biometrics/fingerprint/aidl/default/include/Session.h
@@ -42,6 +42,8 @@
     RESETTING_LOCKOUT,
 };
 
+void onClientDeath(void* cookie);
+
 class Session : public BnSession {
   public:
     Session(int sensorId, int userId, std::shared_ptr<ISessionCallback> cb,
@@ -101,6 +103,8 @@
 
     ndk::ScopedAStatus setIgnoreDisplayTouches(bool shouldIgnore) override;
 
+    binder_status_t linkToDeath(AIBinder* binder);
+
     bool isClosed();
 
   private:
@@ -139,6 +143,9 @@
     // modified from both the main and the worker threads.
     std::atomic<SessionState> mScheduledState;
     std::atomic<SessionState> 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 0000000..3b96d7f
--- /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 <android/binder_process.h>
+#include <fingerprint.sysprop.h>
+#include <gtest/gtest.h>
+
+#include <android-base/logging.h>
+
+#include <aidl/android/hardware/biometrics/fingerprint/BnSessionCallback.h>
+
+#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<int32_t>& /*enrollmentIds*/) override {
+        return ndk::ScopedAStatus::ok();
+    };
+    ::ndk::ScopedAStatus onEnrollmentsRemoved(
+            const std::vector<int32_t>& /*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<TestSessionCallback>();
+        mSession = ndk::SharedRefBase::make<Session>(1, 2, mCb, &mFakeFingerprintEngine, &mWorker);
+        ASSERT_TRUE(mSession != nullptr);
+        mSession->linkToDeath(mCb->asBinder().get());
+    }
+
+    void TearDown() override {}
+
+    std::shared_ptr<Session> mSession;
+    std::shared_ptr<TestSessionCallback> 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<void*>(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();
+}