| /* |
| * 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 |