/* * Copyright (C) 2017 The Android Open Source Project * Copyright (C) 2018-2021 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.1-service.xiaomi_sm6150" #define LOG_VERBOSE "android.hardware.biometrics.fingerprint@2.1-service.xiaomi_sm6150" #include #include #include "BiometricsFingerprint.h" #include #include namespace android { namespace hardware { namespace biometrics { namespace fingerprint { namespace V2_1 { namespace implementation { // Supported fingerprint HAL version static const uint16_t kVersion = HARDWARE_MODULE_API_VERSION(2, 1); using RequestStatus = android::hardware::biometrics::fingerprint::V2_1::RequestStatus; BiometricsFingerprint *BiometricsFingerprint::sInstance = nullptr; BiometricsFingerprint::BiometricsFingerprint() : mClientCallback(nullptr), mDevice(nullptr) { sInstance = this; // keep track of the most recent instance mDevice = openHal(); if (!mDevice) { ALOGE("Can't open HAL module"); } } BiometricsFingerprint::~BiometricsFingerprint() { ALOGV("~BiometricsFingerprint()"); if (mDevice == nullptr) { ALOGE("No valid device"); return; } int err; if (0 != (err = mDevice->common.close( reinterpret_cast(mDevice)))) { ALOGE("Can't close fingerprint module, error: %d", err); return; } mDevice = nullptr; } 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: ALOGE("An unknown error returned from fingerprint vendor library: %d", 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) { *vendorCode = 0; 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; } } ALOGE("Unknown error from fingerprint vendor library: %d", 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) { *vendorCode = 0; 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; } } ALOGE("Unknown acquiredmsg from fingerprint vendor library: %d", info); return FingerprintAcquiredInfo::ACQUIRED_INSUFFICIENT; } Return BiometricsFingerprint::setNotify( const sp& clientCallback) { std::lock_guard lock(mClientCallbackMutex); mClientCallback = clientCallback; // This is here because HAL 2.1 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(mDevice); } Return BiometricsFingerprint::preEnroll() { return mDevice->pre_enroll(mDevice); } Return BiometricsFingerprint::enroll(const hidl_array& hat, uint32_t gid, uint32_t timeoutSec) { const hw_auth_token_t* authToken = reinterpret_cast(hat.data()); return ErrorFilter(mDevice->enroll(mDevice, authToken, gid, timeoutSec)); } Return BiometricsFingerprint::postEnroll() { return ErrorFilter(mDevice->post_enroll(mDevice)); } Return BiometricsFingerprint::getAuthenticatorId() { return mDevice->get_authenticator_id(mDevice); } Return BiometricsFingerprint::cancel() { return ErrorFilter(mDevice->cancel(mDevice)); } Return BiometricsFingerprint::enumerate() { return ErrorFilter(mDevice->enumerate(mDevice)); } Return BiometricsFingerprint::remove(uint32_t gid, uint32_t fid) { return ErrorFilter(mDevice->remove(mDevice, gid, fid)); } Return BiometricsFingerprint::setActiveGroup(uint32_t gid, const hidl_string& storePath) { if (storePath.size() >= PATH_MAX || storePath.size() <= 0) { ALOGE("Bad path length: %zd", storePath.size()); return RequestStatus::SYS_EINVAL; } if (access(storePath.c_str(), W_OK)) { return RequestStatus::SYS_EINVAL; } return ErrorFilter(mDevice->set_active_group(mDevice, gid, storePath.c_str())); } Return BiometricsFingerprint::authenticate(uint64_t operationId, uint32_t gid) { return ErrorFilter(mDevice->authenticate(mDevice, operationId, gid)); } IBiometricsFingerprint* BiometricsFingerprint::getInstance() { if (!sInstance) { sInstance = new BiometricsFingerprint(); } return sInstance; } fingerprint_device_t* getDeviceForVendor(const char *class_name) { int err; const hw_module_t *hw_mdl = nullptr; ALOGD("Opening fingerprint hal library..."); if (0 != (err = hw_get_module_by_class(FINGERPRINT_HARDWARE_MODULE_ID, class_name, &hw_mdl))) { ALOGE("Can't open fingerprint HW Module, class: %s, error: %d", class_name, err); return nullptr; } if (hw_mdl == nullptr) { ALOGE("No valid fingerprint module, class: %s", class_name); return nullptr; } fingerprint_module_t const *module = reinterpret_cast(hw_mdl); if (module->common.methods->open == nullptr) { ALOGE("No valid open method, class: %s", class_name); return nullptr; } hw_device_t *device = nullptr; if (0 != (err = module->common.methods->open(hw_mdl, nullptr, &device))) { ALOGE("Can't open fingerprint methods, class: %s, error: %d", class_name, err); return nullptr; } if (kVersion != device->version) { // enforce version on new devices because of HIDL@2.1 translation layer ALOGE("Wrong fp version. Expected %d, got %d", kVersion, device->version); return nullptr; } fingerprint_device_t* fp_device = reinterpret_cast(device); ALOGI("Loaded fingerprint module, class: %s", class_name); return fp_device; } fingerprint_device_t* getFingerprintDevice() { fingerprint_device_t *fp_device; std::string vendor_modules[] = { "fpc", "fpc_fod", "goodix", "goodix_fod" }; for (const auto& vendor : vendor_modules) { if ((fp_device = getDeviceForVendor(vendor.c_str())) == nullptr) { ALOGE("Failed to load %s fingerprint module", vendor.c_str()); continue; } return fp_device; } return nullptr; } fingerprint_device_t* BiometricsFingerprint::openHal() { int err; fingerprint_device_t *fp_device; fp_device = getFingerprintDevice(); if (fp_device == nullptr) { return nullptr; } if (0 != (err = fp_device->set_notify(fp_device, BiometricsFingerprint::notify))) { ALOGE("Can't register fingerprint module callback, error: %d", err); return nullptr; } return fp_device; } 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) { ALOGE("Receiving callbacks before the client callback is registered."); return; } const uint64_t devId = reinterpret_cast(thisPtr->mDevice); switch (msg->type) { case FINGERPRINT_ERROR: { int32_t vendorCode = 0; FingerprintError result = VendorErrorFilter(msg->data.error, &vendorCode); ALOGD("onError(%d)", result); if (!thisPtr->mClientCallback->onError(devId, result, vendorCode).isOk()) { ALOGE("failed to invoke fingerprint onError callback"); } } break; case FINGERPRINT_ACQUIRED: { int32_t vendorCode = 0; FingerprintAcquiredInfo result = VendorAcquiredFilter(msg->data.acquired.acquired_info, &vendorCode); ALOGD("onAcquired(%d)", result); if (!thisPtr->mClientCallback->onAcquired(devId, result, vendorCode).isOk()) { ALOGE("failed to invoke fingerprint onAcquired callback"); } } break; case FINGERPRINT_TEMPLATE_ENROLLING: ALOGD("onEnrollResult(fid=%d, gid=%d, rem=%d)", msg->data.enroll.finger.fid, msg->data.enroll.finger.gid, 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()) { ALOGE("failed to invoke fingerprint onEnrollResult callback"); } break; case FINGERPRINT_TEMPLATE_REMOVED: ALOGD("onRemove(fid=%d, gid=%d, rem=%d)", msg->data.removed.finger.fid, msg->data.removed.finger.gid, 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()) { ALOGE("failed to invoke fingerprint onRemoved callback"); } break; case FINGERPRINT_AUTHENTICATED: if (msg->data.authenticated.finger.fid != 0) { ALOGD("onAuthenticated(fid=%d, gid=%d)", msg->data.authenticated.finger.fid, msg->data.authenticated.finger.gid); 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()) { ALOGE("failed to invoke fingerprint onAuthenticated callback"); } } else { // Not a recognized fingerprint if (!thisPtr->mClientCallback->onAuthenticated(devId, msg->data.authenticated.finger.fid, msg->data.authenticated.finger.gid, hidl_vec()).isOk()) { ALOGE("failed to invoke fingerprint onAuthenticated callback"); } } break; case FINGERPRINT_TEMPLATE_ENUMERATING: ALOGD("onEnumerate(fid=%d, gid=%d, rem=%d)", msg->data.enumerated.finger.fid, msg->data.enumerated.finger.gid, 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()) { ALOGE("failed to invoke fingerprint onEnumerate callback"); } break; } } #ifdef XIAOMI_FINGERPRINTEXTENSION Return BiometricsFingerprint::extCmd(int32_t cmd, int32_t param) { return mDevice->extCmd(mDevice, cmd, param); } #endif /* XIAOMI_FINGERPRINTEXTENSION */ } // namespace implementation } // namespace V2_1 } // namespace fingerprint } // namespace biometrics } // namespace hardware } // namespace android