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"
+}