/* * Copyright (C) 2019 The LineageOS Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "android.hardware.biometrics.fingerprint@2.3-service-samsung.sm7125" #include #include #include #include #include "BiometricsFingerprint.h" #include #include #include #include #include #include #ifdef HAS_FINGERPRINT_GESTURES #include #endif #define TSP_CMD_PATH "/sys/class/sec/tsp/cmd" #define HBM_PATH "/sys/class/lcd/panel/mask_brightness" namespace android { namespace hardware { namespace biometrics { namespace fingerprint { namespace V2_3 { namespace implementation { using RequestStatus = android::hardware::biometrics::fingerprint::V2_1::RequestStatus; BiometricsFingerprint* BiometricsFingerprint::sInstance = nullptr; template static void set(const std::string& path, const T& value) { std::ofstream file(path); file << value; } std::string getBootloader() { return android::base::GetProperty("ro.boot.bootloader", ""); } BiometricsFingerprint::BiometricsFingerprint() : mClientCallback(nullptr) { sInstance = this; // keep track of the most recent instance if (!openHal()) { LOG(ERROR) << "Can't open HAL module"; } if (getBootloader().find("A525") != std::string::npos) { set(TSP_CMD_PATH, "set_fod_rect,421,2018,659,2256"); } else if (getBootloader().find("A725") != std::string::npos) { set(TSP_CMD_PATH, "set_fod_rect,426,2031,654,2259"); } else { LOG(ERROR) << "Device is not an A52 or A72, not setting set_fod_rect"; } std::ifstream in("/sys/devices/virtual/fingerprint/fingerprint/position"); mIsUdfps = !!in; if (in) in.close(); #ifdef HAS_FINGERPRINT_GESTURES 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"; return; } 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"; return; } 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"; return; } err = ioctl(uinputFd, UI_DEV_CREATE); if (err < 0) { LOG(ERROR) << "Unable to create uinput device"; return; } LOG(INFO) << "Successfully registered uinput-sec-fp for fingerprint gestures"; #endif set(TSP_CMD_PATH, "fod_enable,1,1,0"); } BiometricsFingerprint::~BiometricsFingerprint() { if (ss_fingerprint_close() != 0) { LOG(ERROR) << "Can't close HAL module"; } } Return BiometricsFingerprint::isUdfps(uint32_t) { return mIsUdfps; } Return BiometricsFingerprint::onFingerDown(uint32_t, uint32_t, float, float) { property_set("vendor.finger.down", "1"); std::thread([this]() { std::this_thread::sleep_for(std::chrono::milliseconds(35)); set(HBM_PATH, "331"); }).detach(); request(SEM_REQUEST_TOUCH_EVENT, FINGERPRINT_REQUEST_SESSION_OPEN); return Void(); } Return BiometricsFingerprint::onFingerUp() { request(SEM_REQUEST_TOUCH_EVENT, FINGERPRINT_REQUEST_RESUME); set(HBM_PATH, "0"); return Void(); } Return BiometricsFingerprint::ErrorFilter(int32_t error) { switch (error) { case 0: return RequestStatus::SYS_OK; case -2: return RequestStatus::SYS_ENOENT; case -4: return RequestStatus::SYS_EINTR; case -5: return RequestStatus::SYS_EIO; case -11: return RequestStatus::SYS_EAGAIN; case -12: return RequestStatus::SYS_ENOMEM; case -13: return RequestStatus::SYS_EACCES; case -14: return RequestStatus::SYS_EFAULT; case -16: return RequestStatus::SYS_EBUSY; case -22: return RequestStatus::SYS_EINVAL; case -28: return RequestStatus::SYS_ENOSPC; case -110: return RequestStatus::SYS_ETIMEDOUT; default: LOG(ERROR) << "An unknown error returned from fingerprint vendor library: " << error; return RequestStatus::SYS_UNKNOWN; } } // Translate from errors returned by traditional HAL (see fingerprint.h) to // HIDL-compliant FingerprintError. FingerprintError BiometricsFingerprint::VendorErrorFilter(int32_t error, int32_t* vendorCode) { switch (error) { case FINGERPRINT_ERROR_HW_UNAVAILABLE: return FingerprintError::ERROR_HW_UNAVAILABLE; case FINGERPRINT_ERROR_UNABLE_TO_PROCESS: return FingerprintError::ERROR_UNABLE_TO_PROCESS; case FINGERPRINT_ERROR_TIMEOUT: return FingerprintError::ERROR_TIMEOUT; case FINGERPRINT_ERROR_NO_SPACE: return FingerprintError::ERROR_NO_SPACE; case FINGERPRINT_ERROR_CANCELED: return FingerprintError::ERROR_CANCELED; case FINGERPRINT_ERROR_UNABLE_TO_REMOVE: return FingerprintError::ERROR_UNABLE_TO_REMOVE; case FINGERPRINT_ERROR_LOCKOUT: return FingerprintError::ERROR_LOCKOUT; default: if (error >= FINGERPRINT_ERROR_VENDOR_BASE) { // vendor specific code. *vendorCode = error - FINGERPRINT_ERROR_VENDOR_BASE; return FingerprintError::ERROR_VENDOR; } } LOG(ERROR) << "Unknown error from fingerprint vendor library: " << error; return FingerprintError::ERROR_UNABLE_TO_PROCESS; } // Translate acquired messages returned by traditional HAL (see fingerprint.h) // to HIDL-compliant FingerprintAcquiredInfo. FingerprintAcquiredInfo BiometricsFingerprint::VendorAcquiredFilter(int32_t info, int32_t* vendorCode) { switch (info) { case FINGERPRINT_ACQUIRED_GOOD: return FingerprintAcquiredInfo::ACQUIRED_GOOD; case FINGERPRINT_ACQUIRED_PARTIAL: return FingerprintAcquiredInfo::ACQUIRED_PARTIAL; case FINGERPRINT_ACQUIRED_INSUFFICIENT: return FingerprintAcquiredInfo::ACQUIRED_INSUFFICIENT; case FINGERPRINT_ACQUIRED_IMAGER_DIRTY: return FingerprintAcquiredInfo::ACQUIRED_IMAGER_DIRTY; case FINGERPRINT_ACQUIRED_TOO_SLOW: return FingerprintAcquiredInfo::ACQUIRED_TOO_SLOW; case FINGERPRINT_ACQUIRED_TOO_FAST: return FingerprintAcquiredInfo::ACQUIRED_TOO_FAST; default: if (info >= FINGERPRINT_ACQUIRED_VENDOR_BASE) { // vendor specific code. *vendorCode = info - FINGERPRINT_ACQUIRED_VENDOR_BASE; return FingerprintAcquiredInfo::ACQUIRED_VENDOR; } } LOG(ERROR) << "Unknown acquiredmsg from fingerprint vendor library: " << info; return FingerprintAcquiredInfo::ACQUIRED_INSUFFICIENT; } Return BiometricsFingerprint::setNotify( const sp& clientCallback) { std::lock_guard lock(mClientCallbackMutex); mClientCallback = clientCallback; // This is here because HAL 2.3 doesn't have a way to propagate a // unique token for its driver. Subsequent versions should send a unique // token for each call to setNotify(). This is fine as long as there's only // one fingerprint device on the platform. return reinterpret_cast(this); } Return BiometricsFingerprint::preEnroll() { return ss_fingerprint_pre_enroll(); } Return BiometricsFingerprint::enroll(const hidl_array& hat, uint32_t gid, uint32_t timeoutSec) { const hw_auth_token_t* authToken = reinterpret_cast(hat.data()); #ifdef REQUEST_FORCE_CALIBRATE request(SEM_REQUEST_FORCE_CBGE, 1); #endif return ErrorFilter(ss_fingerprint_enroll(authToken, gid, timeoutSec)); } Return BiometricsFingerprint::postEnroll() { getInstance()->onFingerUp(); return ErrorFilter(ss_fingerprint_post_enroll()); } Return BiometricsFingerprint::getAuthenticatorId() { return ss_fingerprint_get_auth_id(); } Return BiometricsFingerprint::cancel() { int32_t ret = ss_fingerprint_cancel(); getInstance()->onFingerUp(); #ifdef CALL_NOTIFY_ON_CANCEL if (ret == 0) { fingerprint_msg_t msg{}; msg.type = FINGERPRINT_ERROR; msg.data.error = FINGERPRINT_ERROR_CANCELED; notify(&msg); } #endif return ErrorFilter(ret); } Return BiometricsFingerprint::enumerate() { if (ss_fingerprint_enumerate != nullptr) { return ErrorFilter(ss_fingerprint_enumerate()); } return RequestStatus::SYS_UNKNOWN; } Return BiometricsFingerprint::remove(uint32_t gid, uint32_t fid) { return ErrorFilter(ss_fingerprint_remove(gid, fid)); } Return BiometricsFingerprint::setActiveGroup(uint32_t gid, const hidl_string& storePath) { if (storePath.size() >= PATH_MAX || storePath.size() <= 0) { LOG(ERROR) << "Bad path length: " << storePath.size(); return RequestStatus::SYS_EINVAL; } if (access(storePath.c_str(), W_OK)) { return RequestStatus::SYS_EINVAL; } return ErrorFilter(ss_fingerprint_set_active_group(gid, storePath.c_str())); } Return BiometricsFingerprint::authenticate(uint64_t operationId, uint32_t gid) { return ErrorFilter(ss_fingerprint_authenticate(operationId, gid)); } IBiometricsFingerprint* BiometricsFingerprint::getInstance() { if (!sInstance) { sInstance = new BiometricsFingerprint(); } return sInstance; } bool BiometricsFingerprint::openHal() { void* handle = dlopen("libbauthserver.so", RTLD_NOW); if (handle) { int err; ss_fingerprint_close = reinterpret_cast(dlsym(handle, "ss_fingerprint_close")); ss_fingerprint_open = reinterpret_cast(dlsym(handle, "ss_fingerprint_open")); ss_set_notify_callback = reinterpret_cast( dlsym(handle, "ss_set_notify_callback")); ss_fingerprint_pre_enroll = reinterpret_cast( dlsym(handle, "ss_fingerprint_pre_enroll")); ss_fingerprint_enroll = reinterpret_cast(dlsym(handle, "ss_fingerprint_enroll")); ss_fingerprint_post_enroll = reinterpret_cast( dlsym(handle, "ss_fingerprint_post_enroll")); ss_fingerprint_get_auth_id = reinterpret_cast( dlsym(handle, "ss_fingerprint_get_auth_id")); ss_fingerprint_cancel = reinterpret_cast(dlsym(handle, "ss_fingerprint_cancel")); ss_fingerprint_enumerate = reinterpret_cast( dlsym(handle, "ss_fingerprint_enumerate")); ss_fingerprint_remove = reinterpret_cast(dlsym(handle, "ss_fingerprint_remove")); ss_fingerprint_set_active_group = reinterpret_cast( dlsym(handle, "ss_fingerprint_set_active_group")); ss_fingerprint_authenticate = reinterpret_cast( dlsym(handle, "ss_fingerprint_authenticate")); ss_fingerprint_request = reinterpret_cast( 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(BiometricsFingerprint::notify)) != 0) { LOG(ERROR) << "Can't register fingerprint module callback, error: " << err; return false; } return true; } return false; } void BiometricsFingerprint::notify(const fingerprint_msg_t* msg) { BiometricsFingerprint* thisPtr = static_cast(BiometricsFingerprint::getInstance()); std::lock_guard lock(thisPtr->mClientCallbackMutex); if (thisPtr == nullptr || thisPtr->mClientCallback == nullptr) { LOG(ERROR) << "Receiving callbacks before the client callback is registered."; return; } const uint64_t devId = 1; switch (msg->type) { case FINGERPRINT_ERROR: { int32_t vendorCode = 0; FingerprintError result = VendorErrorFilter(msg->data.error, &vendorCode); LOG(DEBUG) << "onError(" << static_cast(result) << ")"; if (!thisPtr->mClientCallback->onError(devId, result, vendorCode).isOk()) { LOG(ERROR) << "failed to invoke fingerprint onError callback"; } getInstance()->onFingerUp(); } break; case FINGERPRINT_ACQUIRED: { if (msg->data.acquired.acquired_info > SEM_FINGERPRINT_EVENT_BASE) { thisPtr->handleEvent(msg->data.acquired.acquired_info); return; } int32_t vendorCode = 0; FingerprintAcquiredInfo result = VendorAcquiredFilter(msg->data.acquired.acquired_info, &vendorCode); LOG(DEBUG) << "onAcquired(" << static_cast(result) << ")"; if (!thisPtr->mClientCallback->onAcquired(devId, result, vendorCode).isOk()) { LOG(ERROR) << "failed to invoke fingerprint onAcquired callback"; } } break; case FINGERPRINT_TEMPLATE_ENROLLING: #ifdef USES_PERCENTAGE_SAMPLES const_cast(msg)->data.enroll.samples_remaining = 100 - msg->data.enroll.samples_remaining; #endif if(msg->data.enroll.samples_remaining == 0) { set(HBM_PATH, "0"); #ifdef CALL_CANCEL_ON_ENROLL_COMPLETION thisPtr->ss_fingerprint_cancel(); #endif } LOG(DEBUG) << "onEnrollResult(fid=" << msg->data.enroll.finger.fid << ", gid=" << msg->data.enroll.finger.gid << ", rem=" << msg->data.enroll.samples_remaining << ")"; if (!thisPtr->mClientCallback ->onEnrollResult(devId, msg->data.enroll.finger.fid, msg->data.enroll.finger.gid, msg->data.enroll.samples_remaining) .isOk()) { LOG(ERROR) << "failed to invoke fingerprint onEnrollResult callback"; } 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 << ")"; if (!thisPtr->mClientCallback ->onRemoved(devId, msg->data.removed.finger.fid, msg->data.removed.finger.gid, msg->data.removed.remaining_templates) .isOk()) { LOG(ERROR) << "failed to invoke fingerprint onRemoved callback"; } 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 uint8_t* hat = reinterpret_cast(&msg->data.authenticated.hat); const hidl_vec token( std::vector(hat, hat + sizeof(msg->data.authenticated.hat))); if (!thisPtr->mClientCallback ->onAuthenticated(devId, msg->data.authenticated.finger.fid, msg->data.authenticated.finger.gid, token) .isOk()) { LOG(ERROR) << "failed to invoke fingerprint onAuthenticated callback"; } getInstance()->onFingerUp(); } else { // Not a recognized fingerprint if (!thisPtr->mClientCallback ->onAuthenticated(devId, msg->data.authenticated.finger.fid, msg->data.authenticated.finger.gid, hidl_vec()) .isOk()) { LOG(ERROR) << "failed to invoke fingerprint onAuthenticated callback"; } } 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 << ")"; if (!thisPtr->mClientCallback ->onEnumerate(devId, msg->data.enumerated.finger.fid, msg->data.enumerated.finger.gid, msg->data.enumerated.remaining_templates) .isOk()) { LOG(ERROR) << "failed to invoke fingerprint onEnumerate callback"; } break; } } void BiometricsFingerprint::handleEvent(int eventCode) { switch (eventCode) { #ifdef HAS_FINGERPRINT_GESTURES case SEM_FINGERPRINT_EVENT_GESTURE_SWIPE_DOWN: case SEM_FINGERPRINT_EVENT_GESTURE_SWIPE_UP: 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; #endif } } int BiometricsFingerprint::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; } int BiometricsFingerprint::waitForSensor(std::chrono::milliseconds pollWait, std::chrono::milliseconds timeOut) { int sensorStatus = SEM_SENSOR_STATUS_WORKING; std::chrono::milliseconds timeWaited = 0ms; while (sensorStatus != SEM_SENSOR_STATUS_OK) { if (sensorStatus == SEM_SENSOR_STATUS_CALIBRATION_ERROR || sensorStatus == SEM_SENSOR_STATUS_ERROR){ return -1; } if (timeWaited >= timeOut) { return -2; } sensorStatus = request(FINGERPRINT_REQUEST_GET_SENSOR_STATUS, 0); std::this_thread::sleep_for(pollWait); timeWaited += pollWait; } return 0; } } // namespace implementation } // namespace V2_3 } // namespace fingerprint } // namespace biometrics } // namespace hardware } // namespace android