aidl: fingerprint: Initial samsung implementation

Change-Id: I2685b176a1b4fb2b094ff58e911997084e42a879
diff --git a/aidl/fingerprint/Android.bp b/aidl/fingerprint/Android.bp
index 8bb8efd..e67e23a 100644
--- a/aidl/fingerprint/Android.bp
+++ b/aidl/fingerprint/Android.bp
@@ -10,17 +10,28 @@
     init_rc: ["android.hardware.biometrics.fingerprint-service.samsung.rc"],
     vintf_fragments: ["android.hardware.biometrics.fingerprint-service.samsung.xml"],
     srcs: [
+        "CancellationSignal.cpp",
         "Fingerprint.cpp",
+        "LegacyHAL.cpp",
+        "LockoutTracker.cpp",
         "Session.cpp",
         "service.cpp",
     ],
     shared_libs: [
         "libbase",
         "libbinder_ndk",
+        "libhardware",
         "android.hardware.biometrics.fingerprint-V3-ndk",
         "android.hardware.biometrics.common-V3-ndk",
-        "android.hardware.biometrics.common.thread",
         "android.hardware.biometrics.common.util",
     ],
+    static_libs: ["libandroid.hardware.biometrics.fingerprint.SamsungProps"],
+    vendor: true,
+}
+
+sysprop_library {
+    name: "android.hardware.biometrics.fingerprint.SamsungProps",
+    srcs: ["fingerprint.sysprop"],
+    property_owner: "Vendor",
     vendor: true,
 }
diff --git a/aidl/fingerprint/CancellationSignal.cpp b/aidl/fingerprint/CancellationSignal.cpp
new file mode 100644
index 0000000..4f49b44
--- /dev/null
+++ b/aidl/fingerprint/CancellationSignal.cpp
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 The LineageOS Project
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "CancellationSignal.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace biometrics {
+namespace fingerprint {
+
+CancellationSignal::CancellationSignal(Session* session)
+    : mSession(session) {
+}
+
+ndk::ScopedAStatus CancellationSignal::cancel() {
+    return mSession->cancel();
+}
+
+} // namespace fingerprint
+} // namespace biometrics
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/aidl/fingerprint/CancellationSignal.h b/aidl/fingerprint/CancellationSignal.h
new file mode 100644
index 0000000..737dd3a
--- /dev/null
+++ b/aidl/fingerprint/CancellationSignal.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2024 The LineageOS Project
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/biometrics/common/BnCancellationSignal.h>
+
+#include "Session.h"
+
+using ::aidl::android::hardware::biometrics::common::BnCancellationSignal;
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace biometrics {
+namespace fingerprint {
+
+class CancellationSignal : public BnCancellationSignal {
+public:
+    CancellationSignal(Session* session);
+    ndk::ScopedAStatus cancel() override;
+
+private:
+    Session* mSession;
+};
+
+} // namespace fingerprint
+} // namespace biometrics
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/aidl/fingerprint/Fingerprint.cpp b/aidl/fingerprint/Fingerprint.cpp
index 2e2d660..4ca160d 100644
--- a/aidl/fingerprint/Fingerprint.cpp
+++ b/aidl/fingerprint/Fingerprint.cpp
@@ -5,21 +5,219 @@
  */
 
 #include "Fingerprint.h"
+#include "VendorConstants.h"
+
+#include <fingerprint.sysprop.h>
+
+#include <android-base/logging.h>
+#include <android-base/parseint.h>
+#include <android-base/strings.h>
+
+#include <fcntl.h>
+#include <linux/uinput.h>
+
+using namespace ::android::fingerprint::samsung;
+
+using ::android::base::ParseInt;
+using ::android::base::Split;
 
 namespace aidl {
 namespace android {
 namespace hardware {
 namespace biometrics {
 namespace fingerprint {
-
-ndk::ScopedAStatus Fingerprint::getSensorProps(std::vector<SensorProps>* /*out*/) {
-    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+namespace {
+constexpr int SENSOR_ID = 0;
+constexpr common::SensorStrength SENSOR_STRENGTH = common::SensorStrength::STRONG;
+constexpr int MAX_ENROLLMENTS_PER_USER = 4;
+constexpr bool SUPPORTS_NAVIGATION_GESTURES = false;
+constexpr char HW_COMPONENT_ID[] = "fingerprintSensor";
+constexpr char HW_VERSION[] = "vendor/model/revision";
+constexpr char FW_VERSION[] = "1.01";
+constexpr char SERIAL_NUMBER[] = "00000001";
+constexpr char SW_COMPONENT_ID[] = "matchingAlgorithm";
+constexpr char SW_VERSION[] = "vendor/version/revision";
 }
 
-ndk::ScopedAStatus Fingerprint::createSession(int32_t /*sensorId*/, int32_t /*userId*/,
-                                              const std::shared_ptr<ISessionCallback>& /*cb*/,
-                                              std::shared_ptr<ISession>* /*out*/) {
-    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+static Fingerprint* sInstance;
+
+Fingerprint::Fingerprint() {
+    sInstance = this; // keep track of the most recent instance
+    if (!mHal.openHal(Fingerprint::notify)) {
+        LOG(ERROR) << "Can't open HAL module";
+    }
+
+    std::string sensorTypeProp = FingerprintHalProperties::type().value_or("");
+    if (sensorTypeProp == "" || sensorTypeProp == "default" || sensorTypeProp == "rear")
+        mSensorType = FingerprintSensorType::REAR;
+    else if (sensorTypeProp == "udfps")
+        mSensorType = FingerprintSensorType::UNDER_DISPLAY_ULTRASONIC;
+    else if (sensorTypeProp == "udfps_optical")
+        mSensorType = FingerprintSensorType::UNDER_DISPLAY_OPTICAL;
+    else if (sensorTypeProp == "side")
+        mSensorType = FingerprintSensorType::POWER_BUTTON;
+    else if (sensorTypeProp == "home")
+        mSensorType = FingerprintSensorType::HOME_BUTTON;
+    else
+        mSensorType = FingerprintSensorType::UNKNOWN;
+
+    mMaxEnrollmentsPerUser =
+            FingerprintHalProperties::max_enrollments_per_user().value_or(MAX_ENROLLMENTS_PER_USER);
+    mSupportsGestures =
+            FingerprintHalProperties::supports_gestures().value_or(SUPPORTS_NAVIGATION_GESTURES);
+
+    if (mSupportsGestures) {
+        mHal.request(FINGERPRINT_REQUEST_NAVIGATION_MODE_START, 1);
+
+        uinputFd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
+        if (uinputFd < 0) {
+            LOG(ERROR) << "Unable to open uinput node";
+            goto skip_uinput_setup;
+        }
+
+        int err = ioctl(uinputFd, UI_SET_EVBIT, EV_KEY) |
+              ioctl(uinputFd, UI_SET_KEYBIT, KEY_UP) |
+              ioctl(uinputFd, UI_SET_KEYBIT, KEY_DOWN);
+        if (err != 0) {
+            LOG(ERROR) << "Unable to enable key events";
+            goto skip_uinput_setup;
+        }
+
+        struct uinput_user_dev uidev;
+        sprintf(uidev.name, "uinput-sec-fp");
+        uidev.id.bustype = BUS_VIRTUAL;
+
+        err = write(uinputFd, &uidev, sizeof(uidev));
+        if (err < 0) {
+            LOG(ERROR) << "Write user device to uinput node failed";
+            goto skip_uinput_setup;
+        }
+
+        err = ioctl(uinputFd, UI_DEV_CREATE);
+        if (err < 0) {
+            LOG(ERROR) << "Unable to create uinput device";
+            goto skip_uinput_setup;
+        }
+
+        LOG(INFO) << "Successfully registered uinput-sec-fp for fingerprint gestures";
+    }
+skip_uinput_setup:
+    return;
+}
+
+ndk::ScopedAStatus Fingerprint::getSensorProps(std::vector<SensorProps>* out) {
+    std::vector<common::ComponentInfo> componentInfo = {
+            {HW_COMPONENT_ID, HW_VERSION, FW_VERSION, SERIAL_NUMBER, "" /* softwareVersion */},
+            {SW_COMPONENT_ID, "" /* hardwareVersion */, "" /* firmwareVersion */,
+            "" /* serialNumber */, SW_VERSION}};
+    common::CommonProps commonProps = {SENSOR_ID, SENSOR_STRENGTH,
+                                       mMaxEnrollmentsPerUser, componentInfo};
+
+    SensorLocation sensorLocation;
+    std::string loc = FingerprintHalProperties::sensor_location().value_or("");
+    std::vector<std::string> dim = Split(loc, "|");
+    if (dim.size() >= 3 && dim.size() <= 4) {
+        ParseInt(dim[0], &sensorLocation.sensorLocationX);
+        ParseInt(dim[1], &sensorLocation.sensorLocationY);
+        ParseInt(dim[2], &sensorLocation.sensorRadius);
+
+        if (dim.size() >= 4)
+            sensorLocation.display = dim[3];
+    } else if(loc.length() > 0) {
+        LOG(WARNING) << "Invalid sensor location input (x|y|radius|display): " << loc;
+    }
+
+    LOG(INFO) << "Sensor type: " << ::android::internal::ToString(mSensorType)
+              << " location: " << sensorLocation.toString();
+
+    *out = {{commonProps,
+             mSensorType,
+             {sensorLocation},
+             mSupportsGestures,
+             false,
+             false,
+             false,
+             std::nullopt}};
+
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Fingerprint::createSession(int32_t /*sensorId*/, int32_t userId,
+                                              const std::shared_ptr<ISessionCallback>& cb,
+                                              std::shared_ptr<ISession>* out) {
+    CHECK(mSession == nullptr || mSession->isClosed()) << "Open session already exists!";
+
+    mSession = SharedRefBase::make<Session>(mHal, userId, cb, mLockoutTracker);
+    *out = mSession;
+
+    mSession->linkToDeath(cb->asBinder().get());
+
+    return ndk::ScopedAStatus::ok();
+}
+
+void Fingerprint::notify(const fingerprint_msg_t* msg) {
+    Fingerprint* thisPtr = sInstance;
+    if (msg->type == FINGERPRINT_ACQUIRED
+        && msg->data.acquired.acquired_info > SEM_FINGERPRINT_EVENT_BASE) {
+        thisPtr->handleEvent(msg->data.acquired.acquired_info);
+        return;
+    }
+
+    if (thisPtr->mSession == nullptr || thisPtr->mSession->isClosed()) {
+        LOG(ERROR) << "Receiving callbacks before a session is opened.";
+        return;
+    }
+
+    thisPtr->mSession->notify(msg);
+}
+
+void Fingerprint::handleEvent(int eventCode) {
+    switch (eventCode) {
+        case SEM_FINGERPRINT_EVENT_GESTURE_SWIPE_DOWN:
+        case SEM_FINGERPRINT_EVENT_GESTURE_SWIPE_UP:
+            if (!mSupportsGestures) return;
+
+            struct input_event event {};
+            int keycode = eventCode == SEM_FINGERPRINT_EVENT_GESTURE_SWIPE_UP ?
+                          KEY_UP : KEY_DOWN;
+
+            // Report the key
+            event.type = EV_KEY;
+            event.code = keycode;
+            event.value = 1;
+            if (write(uinputFd, &event, sizeof(event)) < 0) {
+                LOG(ERROR) << "Write EV_KEY to uinput node failed";
+                return;
+            }
+
+            // Force a flush with an EV_SYN
+            event.type = EV_SYN;
+            event.code = SYN_REPORT;
+            event.value = 0;
+            if (write(uinputFd, &event, sizeof(event)) < 0) {
+                LOG(ERROR) << "Write EV_SYN to uinput node failed";
+                return;
+            }
+
+            // Report the key
+            event.type = EV_KEY;
+            event.code = keycode;
+            event.value = 0;
+            if (write(uinputFd, &event, sizeof(event)) < 0) {
+                LOG(ERROR) << "Write EV_KEY to uinput node failed";
+                return;
+            }
+
+            // Force a flush with an EV_SYN
+            event.type = EV_SYN;
+            event.code = SYN_REPORT;
+            event.value = 0;
+            if (write(uinputFd, &event, sizeof(event)) < 0) {
+                LOG(ERROR) << "Write EV_SYN to uinput node failed";
+                return;
+            }
+        break;
+    }
 }
 
 } // namespace fingerprint
diff --git a/aidl/fingerprint/Fingerprint.h b/aidl/fingerprint/Fingerprint.h
index f4655d7..0928192 100644
--- a/aidl/fingerprint/Fingerprint.h
+++ b/aidl/fingerprint/Fingerprint.h
@@ -8,6 +8,10 @@
 
 #include <aidl/android/hardware/biometrics/fingerprint/BnFingerprint.h>
 
+#include "LegacyHAL.h"
+#include "LockoutTracker.h"
+#include "Session.h"
+
 using ::aidl::android::hardware::biometrics::fingerprint::ISession;
 using ::aidl::android::hardware::biometrics::fingerprint::ISessionCallback;
 using ::aidl::android::hardware::biometrics::fingerprint::SensorProps;
@@ -20,10 +24,25 @@
 
 class Fingerprint : public BnFingerprint {
 public:
+    Fingerprint();
     ndk::ScopedAStatus getSensorProps(std::vector<SensorProps>* _aidl_return) override;
     ndk::ScopedAStatus createSession(int32_t sensorId, int32_t userId,
                                      const std::shared_ptr<ISessionCallback>& cb,
                                      std::shared_ptr<ISession>* out) override;
+
+private:
+    static void notify(
+        const fingerprint_msg_t* msg); /* Static callback for legacy HAL implementation */
+    void handleEvent(int eventCode);
+
+    LegacyHAL mHal;
+    LockoutTracker mLockoutTracker;
+    FingerprintSensorType mSensorType;
+    int mMaxEnrollmentsPerUser;
+    bool mSupportsGestures;
+    int uinputFd;
+
+    std::shared_ptr<Session> mSession;
 };
 
 } // namespace fingerprint
diff --git a/aidl/fingerprint/Legacy2Aidl.h b/aidl/fingerprint/Legacy2Aidl.h
new file mode 100644
index 0000000..939e02e
--- /dev/null
+++ b/aidl/fingerprint/Legacy2Aidl.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2024 The LineageOS Project
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/keymaster/HardwareAuthToken.h>
+
+#include <hardware/hw_auth_token.h>
+
+#include <endian.h>
+
+using aidl::android::hardware::keymaster::HardwareAuthToken;
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace biometrics {
+namespace fingerprint {
+
+inline void translate(const HardwareAuthToken& authToken, hw_auth_token_t& hat) {
+    hat.challenge = authToken.challenge;
+    hat.user_id = authToken.userId;
+    hat.authenticator_id = authToken.authenticatorId;
+    // these are in host order: translate to network order
+    hat.authenticator_type = htobe32(static_cast<uint32_t>(authToken.authenticatorType));
+    hat.timestamp = htobe64(authToken.timestamp.milliSeconds);
+    std::copy(authToken.mac.begin(), authToken.mac.end(), hat.hmac);
+}
+
+inline void translate(const hw_auth_token_t& hat, HardwareAuthToken& authToken) {
+    authToken.challenge = hat.challenge;
+    authToken.userId = hat.user_id;
+    authToken.authenticatorId = hat.authenticator_id;
+    // these are in network order: translate to host
+    authToken.authenticatorType =
+            static_cast<keymaster::HardwareAuthenticatorType>(
+                    be32toh(hat.authenticator_type));
+    authToken.timestamp.milliSeconds = be64toh(hat.timestamp);
+    authToken.mac.insert(authToken.mac.begin(), std::begin(hat.hmac),
+                         std::end(hat.hmac));
+}
+
+} // namespace fingerprint
+} // namespace biometrics
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/aidl/fingerprint/LegacyHAL.cpp b/aidl/fingerprint/LegacyHAL.cpp
new file mode 100644
index 0000000..54f5a35
--- /dev/null
+++ b/aidl/fingerprint/LegacyHAL.cpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2024 The LineageOS Project
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "Fingerprint.h"
+
+#include <android-base/logging.h>
+
+#include <dlfcn.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace biometrics {
+namespace fingerprint {
+
+bool LegacyHAL::openHal(fingerprint_notify_t notify) {
+    void* handle = dlopen("libbauthserver.so", RTLD_NOW);
+    if (handle) {
+        int err;
+
+        ss_fingerprint_close =
+            reinterpret_cast<typeof(ss_fingerprint_close)>(dlsym(handle, "ss_fingerprint_close"));
+        ss_fingerprint_open =
+            reinterpret_cast<typeof(ss_fingerprint_open)>(dlsym(handle, "ss_fingerprint_open"));
+
+        ss_set_notify_callback = reinterpret_cast<typeof(ss_set_notify_callback)>(
+            dlsym(handle, "ss_set_notify_callback"));
+        ss_fingerprint_pre_enroll = reinterpret_cast<typeof(ss_fingerprint_pre_enroll)>(
+            dlsym(handle, "ss_fingerprint_pre_enroll"));
+        ss_fingerprint_enroll =
+            reinterpret_cast<typeof(ss_fingerprint_enroll)>(dlsym(handle, "ss_fingerprint_enroll"));
+        ss_fingerprint_post_enroll = reinterpret_cast<typeof(ss_fingerprint_post_enroll)>(
+            dlsym(handle, "ss_fingerprint_post_enroll"));
+        ss_fingerprint_get_auth_id = reinterpret_cast<typeof(ss_fingerprint_get_auth_id)>(
+            dlsym(handle, "ss_fingerprint_get_auth_id"));
+        ss_fingerprint_cancel =
+            reinterpret_cast<typeof(ss_fingerprint_cancel)>(dlsym(handle, "ss_fingerprint_cancel"));
+        ss_fingerprint_enumerate = reinterpret_cast<typeof(ss_fingerprint_enumerate)>(
+            dlsym(handle, "ss_fingerprint_enumerate"));
+        ss_fingerprint_remove =
+            reinterpret_cast<typeof(ss_fingerprint_remove)>(dlsym(handle, "ss_fingerprint_remove"));
+        ss_fingerprint_set_active_group = reinterpret_cast<typeof(ss_fingerprint_set_active_group)>(
+            dlsym(handle, "ss_fingerprint_set_active_group"));
+        ss_fingerprint_authenticate = reinterpret_cast<typeof(ss_fingerprint_authenticate)>(
+            dlsym(handle, "ss_fingerprint_authenticate"));
+        ss_fingerprint_request = reinterpret_cast<typeof(ss_fingerprint_request)>(
+            dlsym(handle, "ss_fingerprint_request"));
+
+        if ((err = ss_fingerprint_open(nullptr)) != 0) {
+            LOG(ERROR) << "Can't open fingerprint, error: " << err;
+            return false;
+        }
+
+        if ((err = ss_set_notify_callback(notify)) != 0) {
+            LOG(ERROR) << "Can't register fingerprint module callback, error: " << err;
+            return false;
+        }
+
+        return true;
+    }
+
+    return false;
+}
+
+int LegacyHAL::request(int cmd, int param) {
+    // TO-DO: input, output handling not implemented
+    int result = ss_fingerprint_request(cmd, nullptr, 0, nullptr, 0, param);
+    LOG(INFO) << "request(cmd=" << cmd << ", param=" << param << ", result=" << result << ")";
+    return result;
+}
+
+} // namespace fingerprint
+} // namespace biometrics
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/aidl/fingerprint/LegacyHAL.h b/aidl/fingerprint/LegacyHAL.h
new file mode 100644
index 0000000..023a873
--- /dev/null
+++ b/aidl/fingerprint/LegacyHAL.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2024 The LineageOS Project
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#pragma once
+
+#include <hardware/fingerprint.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace biometrics {
+namespace fingerprint {
+
+class LegacyHAL {
+public:
+    bool openHal(fingerprint_notify_t notify);
+    int request(int cmd, int param);
+
+    int (*ss_fingerprint_close)();
+    int (*ss_fingerprint_open)(const char* id);
+
+    int (*ss_set_notify_callback)(fingerprint_notify_t notify);
+    uint64_t (*ss_fingerprint_pre_enroll)();
+    int (*ss_fingerprint_enroll)(const hw_auth_token_t* hat, uint32_t gid, uint32_t timeout_sec);
+    int (*ss_fingerprint_post_enroll)();
+    uint64_t (*ss_fingerprint_get_auth_id)();
+    int (*ss_fingerprint_cancel)();
+    int (*ss_fingerprint_enumerate)();
+    int (*ss_fingerprint_remove)(uint32_t gid, uint32_t fid);
+    int (*ss_fingerprint_set_active_group)(uint32_t gid, const char* store_path);
+    int (*ss_fingerprint_authenticate)(uint64_t operation_id, uint32_t gid);
+    int (*ss_fingerprint_request)(uint32_t cmd, char *inBuf, uint32_t inBuf_length, char *outBuf, uint32_t outBuf_length, uint32_t param);
+};
+
+} // namespace fingerprint
+} // namespace biometrics
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/aidl/fingerprint/LockoutTracker.cpp b/aidl/fingerprint/LockoutTracker.cpp
new file mode 100644
index 0000000..7baa6fd
--- /dev/null
+++ b/aidl/fingerprint/LockoutTracker.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2024 The LineageOS Project
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "Fingerprint.h"
+#include "LockoutTracker.h"
+
+#include <util/Util.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace biometrics {
+namespace fingerprint {
+
+void LockoutTracker::reset(bool clearAttemptCounter) {
+    if (clearAttemptCounter)
+        mFailedCount = 0;
+    mLockoutTimedStart = 0;
+    mCurrentMode = LockoutMode::NONE;
+}
+
+void LockoutTracker::addFailedAttempt() {
+    mFailedCount++;
+
+    if (mFailedCount >= LOCKOUT_PERMANENT_THRESHOLD)
+        mCurrentMode = LockoutMode::PERMANENT;
+    else if (mFailedCount >= LOCKOUT_TIMED_THRESHOLD) {
+        mCurrentMode = LockoutMode::TIMED;
+        mLockoutTimedStart = Util::getSystemNanoTime();
+    }
+}
+
+LockoutMode LockoutTracker::getMode() {
+    if (mCurrentMode == LockoutMode::TIMED) {
+        if (Util::hasElapsed(mLockoutTimedStart, LOCKOUT_TIMED_DURATION)) {
+            mCurrentMode = LockoutMode::NONE;
+            mLockoutTimedStart = 0;
+        }
+    }
+
+    return mCurrentMode;
+}
+
+int64_t LockoutTracker::getLockoutTimeLeft() {
+    int64_t res = 0;
+
+    if (mLockoutTimedStart > 0) {
+        auto now = Util::getSystemNanoTime();
+        auto elapsed = (now - mLockoutTimedStart) / 1000000LL;
+        res = LOCKOUT_TIMED_DURATION - elapsed;
+    }
+
+    return res;
+}
+
+} // namespace fingerprint
+} // namespace biometrics
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/aidl/fingerprint/LockoutTracker.h b/aidl/fingerprint/LockoutTracker.h
new file mode 100644
index 0000000..4e529d2
--- /dev/null
+++ b/aidl/fingerprint/LockoutTracker.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2024 The LineageOS Project
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#pragma once
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace biometrics {
+namespace fingerprint {
+
+#define LOCKOUT_TIMED_THRESHOLD 5
+#define LOCKOUT_TIMED_DURATION 30 * 1000
+#define LOCKOUT_PERMANENT_THRESHOLD 20
+
+enum class LockoutMode {
+    NONE,
+    TIMED,
+    PERMANENT
+};
+
+class LockoutTracker {
+public:
+    void reset(bool clearAttemptCounter);
+    LockoutMode getMode();
+    void addFailedAttempt();
+    int64_t getLockoutTimeLeft();
+
+private:
+    int32_t mFailedCount = 0;
+    int64_t mLockoutTimedStart;
+    LockoutMode mCurrentMode;
+};
+
+} // namespace fingerprint
+} // namespace biometrics
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/aidl/fingerprint/Session.cpp b/aidl/fingerprint/Session.cpp
index 3a1d919..6f65046 100644
--- a/aidl/fingerprint/Session.cpp
+++ b/aidl/fingerprint/Session.cpp
@@ -4,7 +4,19 @@
  * SPDX-License-Identifier: Apache-2.0
  */
 
+#include "CancellationSignal.h"
+#include "Legacy2Aidl.h"
 #include "Session.h"
+#include "VendorConstants.h"
+
+#include <fingerprint.sysprop.h>
+
+#include <android-base/logging.h>
+
+#include <endian.h>
+#include <thread>
+
+using namespace ::android::fingerprint::samsung;
 
 namespace aidl {
 namespace android {
@@ -12,100 +24,399 @@
 namespace biometrics {
 namespace fingerprint {
 
+void onClientDeath(void* cookie) {
+    LOG(INFO) << "FingerprintService has died";
+    Session* session = static_cast<Session*>(cookie);
+    if (session && !session->isClosed()) {
+        session->close();
+    }
+}
+
+Session::Session(LegacyHAL hal, int userId, std::shared_ptr<ISessionCallback> cb,
+                 LockoutTracker lockoutTracker)
+    : mHal(hal),
+      mLockoutTracker(lockoutTracker),
+      mUserId(userId),
+      mCb(cb) {
+    mDeathRecipient = AIBinder_DeathRecipient_new(onClientDeath);
+
+    char filename[64];
+    snprintf(filename, sizeof(filename), "/data/vendor_de/%d/fpdata/");
+    mHal.ss_fingerprint_set_active_group(userId, &filename[0]);
+}
+
 ndk::ScopedAStatus Session::generateChallenge() {
-    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+    LOG(INFO) << "generateChallenge";
+
+    uint64_t challenge = mHal.ss_fingerprint_pre_enroll();
+    mCb->onChallengeGenerated(challenge);
+
+    return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus Session::revokeChallenge(int64_t /*challenge*/) {
-    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ndk::ScopedAStatus Session::revokeChallenge(int64_t challenge) {
+    LOG(INFO) << "revokeChallenge";
+
+    mHal.ss_fingerprint_post_enroll();
+    mCb->onChallengeRevoked(challenge);
+
+    return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus Session::enroll(const HardwareAuthToken& /*hat*/,
-                                   std::shared_ptr<ICancellationSignal>* /*out*/) {
-    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ndk::ScopedAStatus Session::enroll(const HardwareAuthToken& hat,
+                                   std::shared_ptr<ICancellationSignal>* out) {
+    LOG(INFO) << "enroll";
+
+    if (FingerprintHalProperties::force_calibrate().value_or(false)) {
+        mHal.request(SEM_REQUEST_FORCE_CBGE, 1);
+    }
+
+    hw_auth_token_t authToken;
+    translate(hat, authToken);
+
+    int32_t error = mHal.ss_fingerprint_enroll(&authToken, mUserId, 0 /* timeoutSec */);
+    if (error) {
+        LOG(ERROR) << "ss_fingerprint_enroll failed: " << error;
+        mCb->onError(Error::UNABLE_TO_PROCESS, error);
+    }
+
+    *out = SharedRefBase::make<CancellationSignal>(this);
+    return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus Session::authenticate(int64_t /*operationId*/,
-                                         std::shared_ptr<ICancellationSignal>* /*out*/) {
-    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ndk::ScopedAStatus Session::authenticate(int64_t operationId,
+                                         std::shared_ptr<ICancellationSignal>* out) {
+    LOG(INFO) << "authenticate";
+
+    int32_t error = mHal.ss_fingerprint_authenticate(operationId, mUserId);
+    if (error) {
+        LOG(ERROR) << "ss_fingerprint_authenticate failed: " << error;
+        mCb->onError(Error::UNABLE_TO_PROCESS, error);
+    }
+
+    *out = SharedRefBase::make<CancellationSignal>(this);
+    return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus Session::detectInteraction(std::shared_ptr<ICancellationSignal>* /*out*/) {
-    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ndk::ScopedAStatus Session::detectInteraction(std::shared_ptr<ICancellationSignal>* out) {
+    LOG(INFO) << "detectInteraction";
+
+    LOG(DEBUG) << "Detect interaction is not supported";
+    mCb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorCode */);
+
+    *out = SharedRefBase::make<CancellationSignal>(this);
+    return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus Session::enumerateEnrollments() {
-    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+    LOG(INFO) << "enumerateEnrollments";
+
+    int32_t error = mHal.ss_fingerprint_enumerate();
+    if (error)
+        LOG(ERROR) << "ss_fingerprint_enumerate failed: " << error;
+
+    return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus Session::removeEnrollments(const std::vector<int32_t>& /*enrollmentIds*/) {
-    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ndk::ScopedAStatus Session::removeEnrollments(const std::vector<int32_t>& enrollmentIds) {
+    LOG(INFO) << "removeEnrollments, size: " << enrollmentIds.size();
+
+    for (int32_t enrollment : enrollmentIds) {
+        int32_t error = mHal.ss_fingerprint_remove(mUserId, enrollment);
+        if (error)
+            LOG(ERROR) << "ss_fingerprint_remove failed: " << error;
+    }
+
+    return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus Session::getAuthenticatorId() {
-    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+    LOG(INFO) << "getAuthenticatorId";
+
+    mCb->onAuthenticatorIdRetrieved(mHal.ss_fingerprint_get_auth_id());
+
+    return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus Session::invalidateAuthenticatorId() {
-    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+    LOG(INFO) << "invalidateAuthenticatorId";
+
+    mCb->onAuthenticatorIdInvalidated(mHal.ss_fingerprint_get_auth_id());
+
+    return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus Session::resetLockout(const HardwareAuthToken& /*hat*/) {
-    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+    LOG(INFO) << "resetLockout";
+
+    clearLockout(true);
+    mIsLockoutTimerAborted = true;
+
+    return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus Session::close() {
-    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+    LOG(INFO) << "close";
+    mClosed = true;
+    mCb->onSessionClosed();
+    AIBinder_DeathRecipient_delete(mDeathRecipient);
+    return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus Session::onPointerDown(int32_t /*pointerId*/, int32_t /*x*/, int32_t /*y*/, float /*minor*/,
                                           float /*major*/) {
-    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+    LOG(INFO) << "onPointerDown";
+
+    if (FingerprintHalProperties::request_touch_event().value_or(false)) {
+        mHal.request(SEM_REQUEST_TOUCH_EVENT, 2);
+    }
+    checkSensorLockout();
+
+    return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus Session::onPointerUp(int32_t /*pointerId*/) {
-    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+    LOG(INFO) << "onPointerUp";
+
+    if (FingerprintHalProperties::request_touch_event().value_or(false)) {
+        mHal.request(SEM_REQUEST_TOUCH_EVENT, 1);
+    }
+
+    return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus Session::onUiReady() {
-    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+    LOG(INFO) << "onUiReady";
+
+    // TODO: stub
+
+    return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus Session::authenticateWithContext(
-        int64_t /*operationId*/, const OperationContext& /*context*/,
-        std::shared_ptr<ICancellationSignal>* /*out*/) {
-    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+        int64_t operationId, const OperationContext& /*context*/,
+        std::shared_ptr<ICancellationSignal>* out) {
+    return authenticate(operationId, out);
 }
 
-ndk::ScopedAStatus Session::enrollWithContext(const HardwareAuthToken& /*hat*/,
+ndk::ScopedAStatus Session::enrollWithContext(const HardwareAuthToken& hat,
                                               const OperationContext& /*context*/,
-                                              std::shared_ptr<ICancellationSignal>* /*out*/) {
-    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+                                              std::shared_ptr<ICancellationSignal>* out) {
+    return enroll(hat, out);
 }
 
 ndk::ScopedAStatus Session::detectInteractionWithContext(const OperationContext& /*context*/,
-                                              std::shared_ptr<ICancellationSignal>* /*out*/) {
-    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+                                              std::shared_ptr<ICancellationSignal>* out) {
+    return detectInteraction(out);
 }
 
-ndk::ScopedAStatus Session::onPointerDownWithContext(const PointerContext& /*context*/) {
-    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ndk::ScopedAStatus Session::onPointerDownWithContext(const PointerContext& context) {
+    return onPointerDown(context.pointerId, context.x, context.y, context.minor, context.major);
 }
 
-ndk::ScopedAStatus Session::onPointerUpWithContext(const PointerContext& /*context*/) {
-    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ndk::ScopedAStatus Session::onPointerUpWithContext(const PointerContext& context) {
+    return onPointerUp(context.pointerId);
 }
 
 ndk::ScopedAStatus Session::onContextChanged(const OperationContext& /*context*/) {
-    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+    return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus Session::onPointerCancelWithContext(const PointerContext& /*context*/) {
-    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+    return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus Session::setIgnoreDisplayTouches(bool /*shouldIgnore*/) {
-    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Session::cancel() {
+    int32_t ret = mHal.ss_fingerprint_cancel();
+
+    if (ret == 0) {
+        mCb->onError(Error::CANCELED, 0 /* vendorCode */);
+
+        return ndk::ScopedAStatus::ok();
+    } else {
+        return ndk::ScopedAStatus::fromServiceSpecificError(ret);
+    }
+}
+
+binder_status_t Session::linkToDeath(AIBinder* binder) {
+    return AIBinder_linkToDeath(binder, mDeathRecipient, this);
+}
+
+bool Session::isClosed() {
+    return mClosed;
+}
+
+// Translate from errors returned by traditional HAL (see fingerprint.h) to
+// AIDL-compliant Error
+Error Session::VendorErrorFilter(int32_t error, int32_t* vendorCode) {
+    *vendorCode = 0;
+
+    switch (error) {
+        case FINGERPRINT_ERROR_HW_UNAVAILABLE:
+            return Error::HW_UNAVAILABLE;
+        case FINGERPRINT_ERROR_UNABLE_TO_PROCESS:
+            return Error::UNABLE_TO_PROCESS;
+        case FINGERPRINT_ERROR_TIMEOUT:
+            return Error::TIMEOUT;
+        case FINGERPRINT_ERROR_NO_SPACE:
+            return Error::NO_SPACE;
+        case FINGERPRINT_ERROR_CANCELED:
+            return Error::CANCELED;
+        case FINGERPRINT_ERROR_UNABLE_TO_REMOVE:
+            return Error::UNABLE_TO_REMOVE;
+        case FINGERPRINT_ERROR_LOCKOUT: {
+            *vendorCode = FINGERPRINT_ERROR_LOCKOUT;
+            return Error::VENDOR;
+        }
+        default:
+            if (error >= FINGERPRINT_ERROR_VENDOR_BASE) {
+                // vendor specific code.
+                *vendorCode = error - FINGERPRINT_ERROR_VENDOR_BASE;
+                return Error::VENDOR;
+            }
+    }
+    LOG(ERROR) << "Unknown error from fingerprint vendor library: " << error;
+    return Error::UNABLE_TO_PROCESS;
+}
+
+// Translate acquired messages returned by traditional HAL (see fingerprint.h)
+// to AIDL-compliant AcquiredInfo
+AcquiredInfo Session::VendorAcquiredFilter(int32_t info, int32_t* vendorCode) {
+    *vendorCode = 0;
+
+    switch (info) {
+        case FINGERPRINT_ACQUIRED_GOOD:
+            return AcquiredInfo::GOOD;
+        case FINGERPRINT_ACQUIRED_PARTIAL:
+            return AcquiredInfo::PARTIAL;
+        case FINGERPRINT_ACQUIRED_INSUFFICIENT:
+            return AcquiredInfo::INSUFFICIENT;
+        case FINGERPRINT_ACQUIRED_IMAGER_DIRTY:
+            return AcquiredInfo::SENSOR_DIRTY;
+        case FINGERPRINT_ACQUIRED_TOO_SLOW:
+            return AcquiredInfo::TOO_SLOW;
+        case FINGERPRINT_ACQUIRED_TOO_FAST:
+            return AcquiredInfo::TOO_FAST;
+        default:
+            if (info >= FINGERPRINT_ACQUIRED_VENDOR_BASE) {
+                // vendor specific code.
+                *vendorCode = info - FINGERPRINT_ACQUIRED_VENDOR_BASE;
+                return AcquiredInfo::VENDOR;
+            }
+    }
+    LOG(ERROR) << "Unknown acquiredmsg from fingerprint vendor library: " << info;
+    return AcquiredInfo::INSUFFICIENT;
+}
+
+bool Session::checkSensorLockout() {
+    LockoutMode lockoutMode = mLockoutTracker.getMode();
+    if (lockoutMode == LockoutMode::PERMANENT) {
+        LOG(ERROR) << "Fail: lockout permanent";
+        mCb->onLockoutPermanent();
+        mIsLockoutTimerAborted = true;
+        return true;
+    } else if (lockoutMode == LockoutMode::TIMED) {
+        int64_t timeLeft = mLockoutTracker.getLockoutTimeLeft();
+        LOG(ERROR) << "Fail: lockout timed " << timeLeft;
+        mCb->onLockoutTimed(timeLeft);
+        if (!mIsLockoutTimerStarted) startLockoutTimer(timeLeft);
+        return true;
+    }
+    return false;
+}
+
+void Session::clearLockout(bool clearAttemptCounter) {
+    mLockoutTracker.reset(clearAttemptCounter);
+    mCb->onLockoutCleared();
+}
+
+void Session::startLockoutTimer(int64_t timeout) {
+    mIsLockoutTimerAborted = false;
+    std::function<void()> action =
+            std::bind(&Session::lockoutTimerExpired, this);
+    std::thread([timeout, action]() {
+        std::this_thread::sleep_for(std::chrono::milliseconds(timeout));
+        action();
+    }).detach();
+
+    mIsLockoutTimerStarted = true;
+}
+
+void Session::lockoutTimerExpired() {
+    if (!mIsLockoutTimerAborted)
+        clearLockout(false);
+
+    mIsLockoutTimerStarted = false;
+    mIsLockoutTimerAborted = false;
+}
+
+void Session::notify(const fingerprint_msg_t* msg) {
+    switch (msg->type) {
+        case FINGERPRINT_ERROR: {
+            int32_t vendorCode = 0;
+            Error result = VendorErrorFilter(msg->data.error, &vendorCode);
+            LOG(DEBUG) << "onError(" << static_cast<int>(result) << ")";
+            mCb->onError(result, vendorCode);
+        } break;
+        case FINGERPRINT_ACQUIRED: {
+            int32_t vendorCode = 0;
+            AcquiredInfo result =
+                VendorAcquiredFilter(msg->data.acquired.acquired_info, &vendorCode);
+            LOG(DEBUG) << "onAcquired(" << static_cast<int>(result) << ")";
+            mCb->onAcquired(result, vendorCode);
+        } break;
+        case FINGERPRINT_TEMPLATE_ENROLLING:
+            if (FingerprintHalProperties::uses_percentage_samples().value_or(false)) {
+                const_cast<fingerprint_msg_t*>(msg)->data.enroll.samples_remaining =
+                    100 - msg->data.enroll.samples_remaining;
+            }
+            if (FingerprintHalProperties::cancel_on_enroll_completion().value_or(false)) {
+                if (msg->data.enroll.samples_remaining == 0)
+                    mHal.ss_fingerprint_cancel();
+            }
+            LOG(DEBUG) << "onEnrollResult(fid=" << msg->data.enroll.finger.fid
+                       << ", gid=" << msg->data.enroll.finger.gid
+                       << ", rem=" << msg->data.enroll.samples_remaining << ")";
+            mCb->onEnrollmentProgress(msg->data.enroll.finger.fid,
+                                      msg->data.enroll.samples_remaining);
+            break;
+        case FINGERPRINT_TEMPLATE_REMOVED: {
+            LOG(DEBUG) << "onRemove(fid=" << msg->data.removed.finger.fid
+                       << ", gid=" << msg->data.removed.finger.gid
+                       << ", rem=" << msg->data.removed.remaining_templates << ")";
+            std::vector<int> enrollments;
+            enrollments.push_back(msg->data.removed.finger.fid);
+            mCb->onEnrollmentsRemoved(enrollments);
+        } break;
+        case FINGERPRINT_AUTHENTICATED: {
+            LOG(DEBUG) << "onAuthenticated(fid=" << msg->data.authenticated.finger.fid
+                       << ", gid=" << msg->data.authenticated.finger.gid << ")";
+            if (msg->data.authenticated.finger.fid != 0) {
+                const hw_auth_token_t hat = msg->data.authenticated.hat;
+                HardwareAuthToken authToken;
+                translate(hat, authToken);
+
+                mCb->onAuthenticationSucceeded(msg->data.authenticated.finger.fid, authToken);
+                mLockoutTracker.reset(true);
+            } else {
+                mCb->onAuthenticationFailed();
+                mLockoutTracker.addFailedAttempt();
+                checkSensorLockout();
+            }
+        } break;
+        case FINGERPRINT_TEMPLATE_ENUMERATING: {
+            LOG(DEBUG) << "onEnumerate(fid=" << msg->data.enumerated.finger.fid
+                       << ", gid=" << msg->data.enumerated.finger.gid
+                       << ", rem=" << msg->data.enumerated.remaining_templates << ")";
+            std::vector<int> enrollments;
+            enrollments.push_back(msg->data.enumerated.finger.fid);
+            mCb->onEnrollmentsEnumerated(enrollments);
+        } break;
+    }
 }
 
 } // namespace fingerprint
diff --git a/aidl/fingerprint/Session.h b/aidl/fingerprint/Session.h
index 0e314bf..15dfdcb 100644
--- a/aidl/fingerprint/Session.h
+++ b/aidl/fingerprint/Session.h
@@ -7,6 +7,12 @@
 #pragma once
 
 #include <aidl/android/hardware/biometrics/fingerprint/BnSession.h>
+#include <aidl/android/hardware/biometrics/fingerprint/ISessionCallback.h>
+
+#include <hardware/fingerprint.h>
+
+#include "LegacyHAL.h"
+#include "LockoutTracker.h"
 
 using ::aidl::android::hardware::biometrics::common::ICancellationSignal;
 using ::aidl::android::hardware::biometrics::common::OperationContext;
@@ -19,8 +25,12 @@
 namespace biometrics {
 namespace fingerprint {
 
+void onClientDeath(void* cookie);
+
 class Session : public BnSession {
 public:
+    Session(LegacyHAL hal, int userId, std::shared_ptr<ISessionCallback> cb,
+            LockoutTracker lockoutTracker);
     ndk::ScopedAStatus generateChallenge() override;
     ndk::ScopedAStatus revokeChallenge(int64_t challenge) override;
     ndk::ScopedAStatus enroll(const HardwareAuthToken& hat,
@@ -53,6 +63,39 @@
     ndk::ScopedAStatus onContextChanged(const OperationContext& context) override;
     ndk::ScopedAStatus onPointerCancelWithContext(const PointerContext& context) override;
     ndk::ScopedAStatus setIgnoreDisplayTouches(bool shouldIgnore) override;
+
+    ndk::ScopedAStatus cancel();
+    binder_status_t linkToDeath(AIBinder* binder);
+    bool isClosed();
+    void notify(
+        const fingerprint_msg_t* msg);
+
+private:
+    LegacyHAL mHal;
+    LockoutTracker mLockoutTracker;
+    bool mClosed = false;
+
+    Error VendorErrorFilter(int32_t error, int32_t* vendorCode);
+    AcquiredInfo VendorAcquiredFilter(int32_t info, int32_t* vendorCode);
+    bool checkSensorLockout();
+    void clearLockout(bool clearAttemptCounter);
+    void startLockoutTimer(int64_t timeout);
+    void lockoutTimerExpired();
+
+    // lockout timer
+    bool mIsLockoutTimerStarted = false;
+    bool mIsLockoutTimerAborted = false;
+
+    // The user ID for which this session was created.
+    int32_t mUserId;
+
+    // Callback for talking to the framework. This callback must only be called from non-binder
+    // threads to prevent nested binder calls and consequently a binder thread exhaustion.
+    // Practically, it means that this callback should always be called from the worker thread.
+    std::shared_ptr<ISessionCallback> mCb;
+
+    // Binder death handler.
+    AIBinder_DeathRecipient* mDeathRecipient;
 };
 
 } // namespace fingerprint
diff --git a/aidl/fingerprint/VendorConstants.h b/aidl/fingerprint/VendorConstants.h
new file mode 100644
index 0000000..86656b3
--- /dev/null
+++ b/aidl/fingerprint/VendorConstants.h
@@ -0,0 +1,101 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (C) 2020 The LineageOS Project
+
+#pragma once
+
+// Fingerprint requests
+#define FINGERPRINT_REQUEST_ENROLL_SESSION 1002
+#define FINGERPRINT_REQUEST_ENROLL_TYPE 18
+#define FINGERPRINT_REQUEST_ENUMERATE 11
+#define FINGERPRINT_REQUEST_GET_FP_IDS 1003
+#define FINGERPRINT_REQUEST_GET_MAX_TEMPLATE_NUMBER 1004
+#define FINGERPRINT_REQUEST_GET_SENSOR_INFO 5
+#define FINGERPRINT_REQUEST_GET_SENSOR_STATUS 6
+#define FINGERPRINT_REQUEST_GET_TOUCH_CNT 1007
+#define FINGERPRINT_REQUEST_GET_UNIQUE_ID 7
+#define FINGERPRINT_REQUEST_GET_USERIDS 12
+#define FINGERPRINT_REQUEST_GET_VERSION 4
+#define FINGERPRINT_REQUEST_HAS_FEATURE 1006
+#define FINGERPRINT_REQUEST_LOCKOUT 1001
+#define FINGERPRINT_REQUEST_NAVIGATION_LCD_ONOFF 17
+#define FINGERPRINT_REQUEST_NAVIGATION_MODE_END 16
+#define FINGERPRINT_REQUEST_NAVIGATION_MODE_START 15
+#define FINGERPRINT_REQUEST_PAUSE 0
+#define FINGERPRINT_REQUEST_PROCESS_FIDO 9
+#define FINGERPRINT_REQUEST_REMOVE_FINGER 1000
+#define FINGERPRINT_REQUEST_RESUME 1
+#define FINGERPRINT_REQUEST_SENSOR_TEST_NORMALSCAN 3
+#define FINGERPRINT_REQUEST_SESSION_OPEN 2
+#define FINGERPRINT_REQUEST_SET_ACTIVE_GROUP 8
+#define FINGERPRINT_REQUEST_UPDATE_SID 10
+
+#define SEM_REQUEST_FORCE_CBGE 21
+#define SEM_REQUEST_GET_FINGER_ICON_REMAIN_TIME 1010
+#define SEM_REQUEST_GET_SECURITY_LEVEL 30
+#define SEM_REQUEST_GET_SENSOR_TEST_RESULT 19
+#define SEM_REQUEST_GET_TA_VERSION 10000
+#define SEM_REQUEST_GET_TSP_BLOCK_STATUS 0x3F9
+#define SEM_REQUEST_HIDE_INDISPLAY_AUTH_ANIMATION 0x3F4
+#define SEM_REQUEST_INSTALL_TA 10001
+#define SEM_REQUEST_IS_NEW_MATCHER 27
+#define SEM_REQUEST_IS_TEMPLATE_CHANGED 25
+#define SEM_REQUEST_MASK_CTL 0x3F5
+#define SEM_REQUEST_MOVE_INDISPLAY_ICON 0x3F3
+#define SEM_REQUEST_OPTICAL_CALIBRATION 0x3F8
+#define SEM_REQUEST_REMOVE_ALL_USER 0x3F6
+#define SEM_REQUEST_SET_ASP_LEVEL 20
+#define SEM_REQUEST_SET_BOUNCER_SCREEN_STATUS 0x3FA
+#define SEM_REQUEST_SET_SCREEN_STATUS 0x3F0
+#define SEM_REQUEST_SHOW_INDISPLAY_AUTH_ANIMATION 1009
+#define SEM_REQUEST_TOUCH_EVENT 22
+#define SEM_REQUEST_TOUCH_SENSITIVE_CHANGE 0x3F7
+#define SEM_REQUEST_UPDATE_MATCHER 28
+#define SEM_REQUEST_VENDOR_EGIS_CALIBRATION 23
+#define SEM_REQUEST_VENDOR_QCOM_REMOVE_CBGE 24
+#define SEM_REQUEST_WIRELESS_CHARGER_STATUS 29
+
+// Fingerprint aquired codes
+#define SEM_FINGERPRINT_ACQUIRED_DUPLICATED_IMAGE 1002
+#define SEM_FINGERPRINT_ACQUIRED_LIGHT_TOUCH 1003
+#define SEM_FINGERPRINT_ACQUIRED_TSP_BLOCK 1004
+#define SEM_FINGERPRINT_ACQUIRED_TSP_UNBLOCK 1005
+#define SEM_FINGERPRINT_ACQUIRED_WET_FINGER 1001
+
+// Fingerprint errors
+#define SEM_FINGERPRINT_ERROR_CALIBRATION 1001
+#define SEM_FINGERPRINT_ERROR_DISABLED_BIOMETRICS 5002
+#define SEM_FINGERPRINT_ERROR_INVALID_HW 1005
+#define SEM_FINGERPRINT_ERROR_NEED_TO_RETRY 5000
+#define SEM_FINGERPRINT_ERROR_ONE_HAND_MODE 5001
+#define SEM_FINGERPRINT_ERROR_PATTERN_DETECTED 1007
+#define SEM_FINGERPRINT_ERROR_SERVICE_FAILURE 1003
+#define SEM_FINGERPRINT_ERROR_SMART_VIEW 5003
+#define SEM_FINGERPRINT_ERROR_SYSTEM_FAILURE 1002
+#define SEM_FINGERPRINT_ERROR_TA_UPDATE -100
+#define SEM_FINGERPRINT_ERROR_TEMPLATE_CORRUPTED 1004
+#define SEM_FINGERPRINT_ERROR_TEMPLATE_FORMAT_CHANGED 1006
+#define SEM_FINGERPRINT_ERROR_WIRELESS_CHARGING 5004
+
+// Fingerprint events
+#define SEM_FINGERPRINT_EVENT_BASE 10000
+#define SEM_FINGERPRINT_EVENT_CAPTURE_COMPLETED 10003
+#define SEM_FINGERPRINT_EVENT_CAPTURE_FAILED 10006
+#define SEM_FINGERPRINT_EVENT_CAPTURE_READY 10001
+#define SEM_FINGERPRINT_EVENT_CAPTURE_STARTED 10002
+#define SEM_FINGERPRINT_EVENT_CAPTURE_SUCCESS 10005
+#define SEM_FINGERPRINT_EVENT_FACTORY_SNSR_SCRIPT_END 10009
+#define SEM_FINGERPRINT_EVENT_FACTORY_SNSR_SCRIPT_START 10008
+#define SEM_FINGERPRINT_EVENT_FINGER_LEAVE 10004
+#define SEM_FINGERPRINT_EVENT_FINGER_LEAVE_TIMEOUT 10007
+#define SEM_FINGERPRINT_EVENT_GESTURE_DTAP 20003
+#define SEM_FINGERPRINT_EVENT_GESTURE_LPRESS 20004
+#define SEM_FINGERPRINT_EVENT_GESTURE_SWIPE_DOWN 20002
+#define SEM_FINGERPRINT_EVENT_GESTURE_SWIPE_UP 20001
+#define SEM_FINGERPRINT_EVENT_SPEN_CONTROL_OFF 30002
+#define SEM_FINGERPRINT_EVENT_SPEN_CONTROL_ON 30001
+
+// Fingerprint sensor status codes
+#define SEM_SENSOR_STATUS_CALIBRATION_ERROR 100045
+#define SEM_SENSOR_STATUS_ERROR 100042
+#define SEM_SENSOR_STATUS_OK 100040
+#define SEM_SENSOR_STATUS_WORKING 100041
diff --git a/aidl/fingerprint/fingerprint.sysprop b/aidl/fingerprint/fingerprint.sysprop
new file mode 100644
index 0000000..7e3896a
--- /dev/null
+++ b/aidl/fingerprint/fingerprint.sysprop
@@ -0,0 +1,78 @@
+# fingerprint.sysprop
+# module becomes static class (Java) / namespace (C++) for serving API
+module: "android.fingerprint.samsung.FingerprintHalProperties"
+owner: Vendor
+
+# type of fingerprint sensor
+prop {
+    prop_name: "ro.vendor.fingerprint.type"
+    type: String
+    scope: Internal
+    access: Readonly
+    enum_values: "default|rear|udfps|udfps_optical|side|home"
+    api_name: "type"
+}
+
+# max enrollments per user (default: 4)
+prop {
+    prop_name: "ro.vendor.fingerprint.max_enrollments"
+    type: Integer
+    scope: Internal
+    access: Readonly
+    api_name: "max_enrollments_per_user"
+}
+
+# supports navigation gestures
+prop {
+    prop_name: "ro.vendor.fingerprint.supports_gestures"
+    type: Boolean
+    scope: Internal
+    access: Readonly
+    api_name: "supports_gestures"
+}
+
+# sensor location
+#    <x>|<y>|<radius>|display in pixel
+prop {
+    prop_name: "ro.vendor.fingerprint.sensor_location"
+    type: String
+    scope: Internal
+    access: Readonly
+    api_name: "sensor_location"
+}
+
+# force calibration on enroll
+prop {
+    prop_name: "ro.vendor.fingerprint.force_calibrate"
+    type: Boolean
+    scope: Internal
+    access: Readonly
+    api_name: "force_calibrate"
+}
+
+# send touch events to HAL
+prop {
+    prop_name: "ro.vendor.fingerprint.request_touch_event"
+    type: Boolean
+    scope: Internal
+    access: Readonly
+    api_name: "request_touch_event"
+}
+
+# uses percentage samples
+prop {
+    prop_name: "ro.vendor.fingerprint.uses_percentage_samples"
+    type: Boolean
+    scope: Internal
+    access: Readonly
+    api_name: "uses_percentage_samples"
+}
+
+# cancel on completed enrollment
+prop {
+    prop_name: "ro.vendor.fingerprint.cancel_on_enroll_completion"
+    type: Boolean
+    scope: Internal
+    access: Readonly
+    api_name: "cancel_on_enroll_completion"
+}