r8s:import fingerprint HAL from hardware/samsung
This commit is contained in:
@@ -33,6 +33,10 @@ PRODUCT_PACKAGES += \
|
||||
TARGET_SCREEN_HEIGHT := 2400
|
||||
TARGET_SCREEN_WIDTH := 1080
|
||||
|
||||
# Fingerprint
|
||||
PRODUCT_PACKAGES += \
|
||||
android.hardware.biometrics.fingerprint-service.samsung-r8s
|
||||
|
||||
# Overlays
|
||||
DEVICE_PACKAGE_OVERLAYS += $(LOCAL_PATH)/overlay
|
||||
|
||||
|
||||
37
fingerprint/Android.bp
Normal file
37
fingerprint/Android.bp
Normal file
@@ -0,0 +1,37 @@
|
||||
//
|
||||
// Copyright (C) 2024 The LineageOS Project
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
cc_binary {
|
||||
name: "android.hardware.biometrics.fingerprint-service.samsung-r8s",
|
||||
relative_install_path: "hw",
|
||||
init_rc: ["android.hardware.biometrics.fingerprint-service.samsung-r8s.rc"],
|
||||
vintf_fragments: ["android.hardware.biometrics.fingerprint-service.samsung-r8s.xml"],
|
||||
srcs: [
|
||||
"CancellationSignal.cpp",
|
||||
"Fingerprint.cpp",
|
||||
"LegacyHAL.cpp",
|
||||
"LockoutTracker.cpp",
|
||||
"Session.cpp",
|
||||
"service.cpp",
|
||||
],
|
||||
shared_libs: [
|
||||
"libbase",
|
||||
"libbinder_ndk",
|
||||
"libhardware",
|
||||
"android.hardware.biometrics.fingerprint-V4-ndk",
|
||||
"android.hardware.biometrics.common-V4-ndk",
|
||||
"android.hardware.biometrics.common.util",
|
||||
],
|
||||
static_libs: ["libandroid.hardware.biometrics.fingerprint.SamsungProps.r8s"],
|
||||
vendor: true,
|
||||
}
|
||||
|
||||
sysprop_library {
|
||||
name: "android.hardware.biometrics.fingerprint.SamsungProps.r8s",
|
||||
srcs: ["fingerprint.sysprop"],
|
||||
property_owner: "Vendor",
|
||||
vendor: true,
|
||||
}
|
||||
27
fingerprint/CancellationSignal.cpp
Normal file
27
fingerprint/CancellationSignal.cpp
Normal file
@@ -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
|
||||
34
fingerprint/CancellationSignal.h
Normal file
34
fingerprint/CancellationSignal.h
Normal file
@@ -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
|
||||
232
fingerprint/Fingerprint.cpp
Normal file
232
fingerprint/Fingerprint.cpp
Normal file
@@ -0,0 +1,232 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The LineageOS Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#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 {
|
||||
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";
|
||||
}
|
||||
|
||||
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;
|
||||
case SEM_FINGERPRINT_EVENT_CAPTURE_READY: {
|
||||
if (mSession != nullptr && !mSession->isClosed()) {
|
||||
mSession->onCaptureReady();
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace fingerprint
|
||||
} // namespace biometrics
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
||||
52
fingerprint/Fingerprint.h
Normal file
52
fingerprint/Fingerprint.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The LineageOS Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#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;
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace biometrics {
|
||||
namespace fingerprint {
|
||||
|
||||
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
|
||||
} // namespace biometrics
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
||||
50
fingerprint/Legacy2Aidl.h
Normal file
50
fingerprint/Legacy2Aidl.h
Normal file
@@ -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
|
||||
83
fingerprint/LegacyHAL.cpp
Normal file
83
fingerprint/LegacyHAL.cpp
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* 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)
|
||||
handle = dlopen("libsfp_sensor.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
|
||||
42
fingerprint/LegacyHAL.h
Normal file
42
fingerprint/LegacyHAL.h
Normal file
@@ -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
|
||||
63
fingerprint/LockoutTracker.cpp
Normal file
63
fingerprint/LockoutTracker.cpp
Normal file
@@ -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
|
||||
42
fingerprint/LockoutTracker.h
Normal file
42
fingerprint/LockoutTracker.h
Normal file
@@ -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
|
||||
465
fingerprint/Session.cpp
Normal file
465
fingerprint/Session.cpp
Normal file
@@ -0,0 +1,465 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The LineageOS Project
|
||||
*
|
||||
* 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 <dirent.h>
|
||||
#include <endian.h>
|
||||
#include <thread>
|
||||
|
||||
using namespace ::android::fingerprint::samsung;
|
||||
using namespace ::std::chrono_literals;
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
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), FINGERPRINT_DATA_DIR, userId);
|
||||
mHal.ss_fingerprint_set_active_group(userId, filename);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Session::generateChallenge() {
|
||||
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) {
|
||||
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) {
|
||||
LOG(INFO) << "enroll";
|
||||
|
||||
if (FingerprintHalProperties::force_calibrate().value_or(false)) {
|
||||
mCaptureReady = 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);
|
||||
}
|
||||
|
||||
if (FingerprintHalProperties::force_calibrate().value_or(false)) {
|
||||
while (!mCaptureReady) {
|
||||
std::this_thread::sleep_for(100ms);
|
||||
}
|
||||
}
|
||||
|
||||
*out = SharedRefBase::make<CancellationSignal>(this);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
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) {
|
||||
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() {
|
||||
LOG(INFO) << "enumerateEnrollments";
|
||||
|
||||
if (mHal.ss_fingerprint_enumerate) {
|
||||
int32_t error = mHal.ss_fingerprint_enumerate();
|
||||
if (error)
|
||||
LOG(ERROR) << "ss_fingerprint_enumerate failed: " << error;
|
||||
} else {
|
||||
std::vector<int> enrollments;
|
||||
char filename[64];
|
||||
snprintf(filename, sizeof(filename), FINGERPRINT_DATA_DIR, mUserId);
|
||||
|
||||
DIR* directory = opendir(filename);
|
||||
if (directory) {
|
||||
struct dirent* entry;
|
||||
while ((entry = readdir(directory))) {
|
||||
int uid, fid;
|
||||
if (sscanf(entry->d_name, "User_%d_%dtmpl.dat", &uid, &fid)) {
|
||||
if (uid == mUserId)
|
||||
enrollments.push_back(fid);
|
||||
}
|
||||
}
|
||||
closedir(directory);
|
||||
} else {
|
||||
LOG(WARNING) << "Failed to open " << filename;
|
||||
}
|
||||
|
||||
mCb->onEnrollmentsEnumerated(enrollments);
|
||||
}
|
||||
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
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() {
|
||||
LOG(INFO) << "getAuthenticatorId";
|
||||
|
||||
mCb->onAuthenticatorIdRetrieved(mHal.ss_fingerprint_get_auth_id());
|
||||
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Session::invalidateAuthenticatorId() {
|
||||
LOG(INFO) << "invalidateAuthenticatorId";
|
||||
|
||||
mCb->onAuthenticatorIdInvalidated(mHal.ss_fingerprint_get_auth_id());
|
||||
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Session::resetLockout(const HardwareAuthToken& /*hat*/) {
|
||||
LOG(INFO) << "resetLockout";
|
||||
|
||||
clearLockout(true);
|
||||
mIsLockoutTimerAborted = true;
|
||||
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Session::close() {
|
||||
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*/) {
|
||||
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*/) {
|
||||
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() {
|
||||
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 authenticate(operationId, out);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Session::enrollWithContext(const HardwareAuthToken& hat,
|
||||
const OperationContext& /*context*/,
|
||||
std::shared_ptr<ICancellationSignal>* out) {
|
||||
return enroll(hat, out);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Session::detectInteractionWithContext(const OperationContext& /*context*/,
|
||||
std::shared_ptr<ICancellationSignal>* out) {
|
||||
return detectInteraction(out);
|
||||
}
|
||||
|
||||
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 onPointerUp(context.pointerId);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Session::onContextChanged(const OperationContext& /*context*/) {
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Session::onPointerCancelWithContext(const PointerContext& /*context*/) {
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Session::setIgnoreDisplayTouches(bool /*shouldIgnore*/) {
|
||||
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 << ")";
|
||||
static std::vector<int> enrollments;
|
||||
enrollments.push_back(msg->data.enumerated.finger.fid);
|
||||
if (msg->data.enumerated.remaining_templates == 0) {
|
||||
mCb->onEnrollmentsEnumerated(enrollments);
|
||||
enrollments.clear();
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void Session::onCaptureReady() {
|
||||
mCaptureReady = true;
|
||||
}
|
||||
|
||||
} // namespace fingerprint
|
||||
} // namespace biometrics
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
||||
109
fingerprint/Session.h
Normal file
109
fingerprint/Session.h
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The LineageOS Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#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"
|
||||
|
||||
#define FINGERPRINT_DATA_DIR "/data/vendor/biometrics/fp/User_%d/"
|
||||
|
||||
using ::aidl::android::hardware::biometrics::common::ICancellationSignal;
|
||||
using ::aidl::android::hardware::biometrics::common::OperationContext;
|
||||
using ::aidl::android::hardware::biometrics::fingerprint::PointerContext;
|
||||
using ::aidl::android::hardware::keymaster::HardwareAuthToken;
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
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,
|
||||
std::shared_ptr<ICancellationSignal>* out) override;
|
||||
ndk::ScopedAStatus authenticate(int64_t operationId,
|
||||
std::shared_ptr<ICancellationSignal>* out) override;
|
||||
ndk::ScopedAStatus detectInteraction(
|
||||
std::shared_ptr<ICancellationSignal>* out) override;
|
||||
ndk::ScopedAStatus enumerateEnrollments() override;
|
||||
ndk::ScopedAStatus removeEnrollments(const std::vector<int32_t>& enrollmentIds) override;
|
||||
ndk::ScopedAStatus getAuthenticatorId() override;
|
||||
ndk::ScopedAStatus invalidateAuthenticatorId() override;
|
||||
ndk::ScopedAStatus resetLockout(const HardwareAuthToken& hat) override;
|
||||
ndk::ScopedAStatus close() override;
|
||||
ndk::ScopedAStatus onPointerDown(int32_t pointerId, int32_t x, int32_t y, float minor,
|
||||
float major) override;
|
||||
ndk::ScopedAStatus onPointerUp(int32_t pointerId) override;
|
||||
ndk::ScopedAStatus onUiReady() override;
|
||||
ndk::ScopedAStatus authenticateWithContext(
|
||||
int64_t operationId, const OperationContext& context,
|
||||
std::shared_ptr<ICancellationSignal>* out) override;
|
||||
ndk::ScopedAStatus enrollWithContext(
|
||||
const HardwareAuthToken& hat, const OperationContext& context,
|
||||
std::shared_ptr<ICancellationSignal>* out) override;
|
||||
ndk::ScopedAStatus detectInteractionWithContext(
|
||||
const OperationContext& context,
|
||||
std::shared_ptr<ICancellationSignal>* out) override;
|
||||
ndk::ScopedAStatus onPointerDownWithContext(const PointerContext& context) override;
|
||||
ndk::ScopedAStatus onPointerUpWithContext(const PointerContext& context) override;
|
||||
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);
|
||||
void onCaptureReady();
|
||||
|
||||
private:
|
||||
LegacyHAL mHal;
|
||||
LockoutTracker mLockoutTracker;
|
||||
bool mClosed = false;
|
||||
bool mCaptureReady = 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
|
||||
} // namespace biometrics
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
||||
101
fingerprint/VendorConstants.h
Normal file
101
fingerprint/VendorConstants.h
Normal file
@@ -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
|
||||
@@ -0,0 +1,5 @@
|
||||
service vendor.fingerprint-default /vendor/bin/hw/android.hardware.biometrics.fingerprint-service.samsung-r8s
|
||||
class hal
|
||||
user system
|
||||
group system input uhid
|
||||
shutdown critical
|
||||
@@ -0,0 +1,6 @@
|
||||
<manifest version="1.0" type="device">
|
||||
<hal format="aidl">
|
||||
<name>android.hardware.biometrics.fingerprint</name>
|
||||
<fqname>IFingerprint/default</fqname>
|
||||
</hal>
|
||||
</manifest>
|
||||
78
fingerprint/fingerprint.sysprop
Normal file
78
fingerprint/fingerprint.sysprop
Normal file
@@ -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"
|
||||
}
|
||||
25
fingerprint/service.cpp
Normal file
25
fingerprint/service.cpp
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The LineageOS Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "Fingerprint.h"
|
||||
|
||||
#include <android/binder_manager.h>
|
||||
#include <android/binder_process.h>
|
||||
#include <android-base/logging.h>
|
||||
|
||||
using ::aidl::android::hardware::biometrics::fingerprint::Fingerprint;
|
||||
|
||||
int main() {
|
||||
ABinderProcess_setThreadPoolMaxThreadCount(0);
|
||||
std::shared_ptr<Fingerprint> fingerprint = ndk::SharedRefBase::make<Fingerprint>();
|
||||
|
||||
const std::string instance = std::string() + Fingerprint::descriptor + "/default";
|
||||
binder_status_t status = AServiceManager_addService(fingerprint->asBinder().get(), instance.c_str());
|
||||
CHECK(status == STATUS_OK);
|
||||
|
||||
ABinderProcess_joinThreadPool();
|
||||
return EXIT_FAILURE; // should not reach
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
ro.vendor.fingerprint.sensor_location=540|2150|120
|
||||
ro.vendor.fingerprint.type=udfps_optical
|
||||
ro.vendor.fingerprint.request_touch_event=true
|
||||
ro.vendor.fingerprint.cancel_on_enroll_completion-true
|
||||
|
||||
# Wifi
|
||||
ro.vendor.wifi.sap.interface=wlan1
|
||||
|
||||
Reference in New Issue
Block a user