IFAAService: Wire up oplus fingerprint pay AIDL

Change-Id: Ibbac7e3c4d6591b712cbdcfb3eda955fbb78f8f3
This commit is contained in:
dianlujitao
2025-08-05 10:38:08 +08:00
committed by Bruno Martins
parent 6be8136317
commit d3b35847b1
7 changed files with 147 additions and 121 deletions

View File

@@ -1,5 +1,5 @@
//
// Copyright (C) 2022-2024 The LineageOS Project
// Copyright (C) 2022-2025 The LineageOS Project
//
// SPDX-License-Identifier: Apache-2.0
//
@@ -15,8 +15,7 @@ android_app {
},
static_libs: [
"android.hidl.base-V1.0-java",
"vendor.xiaomi.hardware.mlipay-V1.1-java",
"vendor.oplus.hardware.biometrics.fingerprintpay-V1-java",
],
certificate: "platform",

View File

@@ -1,12 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
SPDX-FileCopyrightText: 2022-2024 The LineageOS Project
SPDX-FileCopyrightText: 2022-2025 The LineageOS Project
SPDX-License-Identifier: Apache-2.0
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:sharedUserId="android.uid.system"
package="org.ifaa.aidl.manager">
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
<application
android:label="@string/app_name"
android:persistent="true">

View File

@@ -5,44 +5,42 @@
package org.ifaa.aidl.manager
import android.app.KeyguardManager
import android.app.Service
import android.content.Intent
import android.os.Build
import android.os.IHwBinder
import android.graphics.Point
import android.hardware.fingerprint.FingerprintManager
import android.os.IBinder
import android.os.ServiceManager
import android.os.SystemProperties
import android.provider.Settings
import android.util.Log
import org.ifaa.aidl.manager.IfaaManagerService
import android.view.WindowManager
import org.json.JSONObject
import vendor.xiaomi.hardware.mlipay.V1_1.IMlipayService
import vendor.oplus.hardware.biometrics.fingerprintpay.IFingerprintPay
class IfaaService : Service() {
private var _mlipayService: IMlipayService? = null
private var _fpPayService: IFingerprintPay? = null
private val mlipayServiceDeathRecipient = IHwBinder.DeathRecipient {
Log.i(LOG_TAG, "mlipay service died")
_mlipayService = null
private val fpPayServiceDeathRecipient = IBinder.DeathRecipient {
Log.i(LOG_TAG, "aidl FingerprintPay hal died, reset hal proxy!")
_fpPayService = null
}
private val mBinder = object : IfaaManagerService.Stub() {
override fun getSupportBIOTypes(): Int {
val fpVendor = SystemProperties.get(FP_VENDOR_PROP, "")
val isUdfps = SystemProperties.getBoolean(IS_UDFPS_PROP, false)
private val fingerprintManager by lazy { getSystemService(FingerprintManager::class.java)!! }
private val keyguardManager by lazy { getSystemService(KeyguardManager::class.java)!! }
private val windowManager by lazy { getSystemService(WindowManager::class.java)!! }
val supportedBioMask = when (!invalidFpVendors.contains(fpVendor.lowercase())) {
true -> AUTH_TYPE_FINGERPRINT or AUTH_TYPE_IRIS
else -> AUTH_TYPE_IRIS
override fun onBind(intent: Intent) = object : IfaaManagerService.Stub() {
private val _supportBIOTypes by lazy {
when (SystemProperties.get(FP_TYPE_PROP, "")) {
"back", "side", "front" -> AUTH_TYPE_FINGERPRINT
"ultrasonic", "optical" -> AUTH_TYPE_OPTICAL_FINGERPRINT
else -> AUTH_TYPE_NOT_SUPPORT
}
}
val ifaaProp = SystemProperties.getInt(
SUPPORTED_BIO_MASK_PROP, 0
) and supportedBioMask or when (isUdfps) {
true -> AUTH_TYPE_OPTICAL_FINGERPRINT
else -> 0
}
return ifaaProp
}
override fun getSupportBIOTypes() = _supportBIOTypes
override fun startBIOManager(authType: Int) = when (authType) {
AUTH_TYPE_FINGERPRINT -> {
@@ -58,126 +56,142 @@ class IfaaService : Service() {
else -> COMMAND_FAIL
}
override fun getDeviceModel() = "${Build.MANUFACTURER}-${Build.DEVICE}"
private val _deviceModel by lazy { SystemProperties.get(IFAA_MODEL_PROP, "OPLUS-Default") }
override fun getDeviceModel() = _deviceModel
override fun processCmd(param: ByteArray) = getMlipayService()?.let { mlipayService ->
var receiveBuffer: ByteArray? = null
val paramByteArray = ArrayList<Byte>().apply {
for (byte in param) {
add(byte)
}
}
try {
val receiveBufferByteArray = mlipayService.invoke_command(
paramByteArray, paramByteArray.size
)
receiveBuffer = receiveBufferByteArray.toByteArray()
override fun processCmd(param: ByteArray) = try {
getFpPayService()?.ifaa_invoke_command(param)
} catch (e: Exception) {
Log.e(LOG_TAG, "processCmdImpl: mlipay invoke_command failed", e)
}
receiveBuffer
Log.e(LOG_TAG, "processCmdImpl: ifaa_invoke_command aidl failed", e)
null
}
override fun getVersion() = 4
override fun getExtInfo(authType: Int, keyExtInfo: String) = initExtString()
override fun getExtInfo(authType: Int, keyExtInfo: String) = when (keyExtInfo) {
KEY_GET_SENSOR_LOCATION -> initExtString()
else -> ""
}
override fun setExtInfo(authType: Int, keyExtInfo: String, valExtInfo: String) {
// Do nothing
}
override fun getEnabled(bioType: Int) = when (bioType) {
AUTH_TYPE_FINGERPRINT -> BIOMETRICS_AVAILABLE
else -> SCREEN_LOCK_NONE
override fun getEnabled(bioType: Int): Int {
if (!keyguardManager.isKeyguardSecure) {
Log.e(LOG_TAG, "No secure keyguard set.")
return BIOMETRIC_NOUSE_NOSET_KEYGUARD
}
override fun getIDList(bioType: Int): IntArray {
var idList = IntArray(0)
return when (bioType) {
AUTH_TYPE_FINGERPRINT -> when {
!fingerprintManager.isHardwareDetected -> {
Log.e(LOG_TAG, "Fingerprint hardware not available!")
BIOMETRIC_NOUSE_SYSTEMLOCKED
}
getMlipayService()?.let { mlipayService ->
try {
val idListAL = mlipayService.ifaa_get_idlist(bioType)
fingerprintManager.enrolledFingerprints.isNullOrEmpty() -> {
Log.e(LOG_TAG, "Fingerprint not enrolled!")
BIOMETRIC_NOUSE_NOT_ENROLLED
}
idList = idListAL.toIntArray()
} catch (e: Exception) {
Log.e(LOG_TAG, "getIDListImpl: mlipay ifaa_get_idlist failed", e)
else -> BIOMETRIC_USE_READY
}
else -> 0
}
}
return idList
override fun getIDList(bioType: Int): IntArray? = when (bioType) {
AUTH_TYPE_FINGERPRINT -> {
val enrolledFingerprintIds = fingerprintManager.enrolledFingerprints?.map {
it.biometricId
}?.toIntArray()
Log.w(LOG_TAG, "getIDList: ${enrolledFingerprintIds}!")
enrolledFingerprintIds
}
else -> null
}
}
override fun onBind(intent: Intent) = mBinder
private fun getMlipayService() = _mlipayService ?: runCatching {
IMlipayService.getService(true)
}.onSuccess {
_mlipayService = it
it.linkToDeath(mlipayServiceDeathRecipient, 0)
}.getOrNull()
private fun initExtString(): String {
val obj = JSONObject()
val keyInfo = JSONObject()
val xy = SystemProperties.get(UDFPS_LOCATION_X_Y_PROP, "")
val wh = SystemProperties.get(UDFPS_SIZE_W_H_PROP, "")
try {
if (!validateVal(xy) || !validateVal(wh)) {
Log.e(LOG_TAG, "initExtString: invalidate, xy: $xy, wh: $wh")
return ""
}
val split = xy.split(",")
val split2 = wh.split(",")
keyInfo.put("startX", split[0].toInt())
keyInfo.put("startY", split[1].toInt())
keyInfo.put("width", split2[0].toInt())
keyInfo.put("height", split2[1].toInt())
keyInfo.put("navConflict", true)
obj.put("type", 0)
obj.put("fullView", keyInfo)
return obj.toString()
} catch (e: Exception) {
Log.e(LOG_TAG, "initExtString: Exception, xy: $xy, wh: $wh", e)
return ""
private fun getFpPayService() = _fpPayService ?: run {
val binder = ServiceManager.getService("${IFingerprintPay.DESCRIPTOR}/default")
IFingerprintPay.Stub.asInterface(binder)?.also {
binder.linkToDeath(fpPayServiceDeathRecipient, 0)
_fpPayService = it
}
}
private fun validateVal(str: String) = !"".equals(str, ignoreCase = true) && str.contains(",")
private val defaultDisplayDimension by lazy {
val dim1 = displayNoVerify?.supportedModes?.maxByOrNull { it.physicalHeight }
?.run { Point(physicalWidth, physicalHeight) }
val dim2 = windowManager.maximumWindowMetrics.bounds
.run { Point(width(), height()) }
dim1?.let { Point(maxOf(dim1.x, dim2.x), maxOf(dim1.y, dim2.y)) } ?: dim2
}
private val iconDiameter by lazy { SystemProperties.getInt(FP_ICON_SIZE_PROP, 190) }
// Coordinates of the upper left corner
private val iconLocation by lazy {
val iconLocationBottom = SystemProperties.getInt(FP_ICON_LOCATION_PROP, 278)
Point(
(defaultDisplayDimension.x - iconDiameter) / 2,
defaultDisplayDimension.y - iconLocationBottom - iconDiameter / 2
)
}
private fun initExtString() = run {
val displayDimension = windowManager.maximumWindowMetrics.bounds.run {
Point(width(), height())
}
val scale = { pos: Point ->
Point(
pos.x * displayDimension.x / defaultDisplayDimension.x,
pos.y * displayDimension.y / defaultDisplayDimension.y
)
}
val scaledLocation = scale(iconLocation)
val scaledDiameter = scale(Point(iconDiameter, iconDiameter))
JSONObject().apply {
put("type", 0)
put("fullView", JSONObject().apply {
put("startX", scaledLocation.x)
put("startY", scaledLocation.y)
put("width", scaledDiameter.x)
put("height", scaledDiameter.y)
put("navConflict", true)
})
}.toString()
}
companion object {
private val LOG_TAG = IfaaService::class.simpleName!!
private const val AUTH_TYPE_NOT_SUPPORT = 0
private const val AUTH_TYPE_FINGERPRINT = 1
private const val AUTH_TYPE_IRIS = 1.shl(1)
private const val AUTH_TYPE_OPTICAL_FINGERPRINT = 1.shl(2)
private const val AUTH_TYPE_OPTICAL_FINGERPRINT = 1.shl(4).or(AUTH_TYPE_FINGERPRINT)
private const val BIOMETRICS_AVAILABLE = 1000
private const val SCREEN_LOCK_NONE = 1003
private const val BIOMETRIC_USE_READY = 1000
private const val BIOMETRIC_NOUSE_SYSTEMLOCKED = 1001
private const val BIOMETRIC_NOUSE_NOT_ENROLLED = 1002
private const val BIOMETRIC_NOUSE_NOSET_KEYGUARD = 1003
private const val COMMAND_OK = 0
private const val COMMAND_FAIL = -1
private const val SUPPORTED_BIO_MASK_PROP = "persist.vendor.sys.pay.ifaa"
private const val FP_VENDOR_PROP = "persist.vendor.sys.fp.vendor"
private const val IS_UDFPS_PROP = "ro.hardware.fp.udfps"
private const val UDFPS_LOCATION_X_Y_PROP = "persist.vendor.sys.fp.udfps.location.X_Y"
private const val UDFPS_SIZE_W_H_PROP = "persist.vendor.sys.fp.udfps.size.width_height"
// Populated by fingerprint HAL
private const val FP_TYPE_PROP = "persist.vendor.fingerprint.sensor_type"
private const val FP_ICON_SIZE_PROP = "persist.vendor.fingerprint.optical.iconsize"
private const val FP_ICON_LOCATION_PROP = "persist.vendor.fingerprint.optical.iconlocation"
private val invalidFpVendors = arrayOf(
"",
"none",
)
// NOTE: Populate ifaaModel from /my_stock/etc/sys_alipay_model_list.json
private const val IFAA_MODEL_PROP = "sys.oplus.ifaa.model"
private const val KEY_GET_SENSOR_LOCATION = "org.ifaa.ext.key.GET_SENSOR_LOCATION"
}
}

View File

@@ -0,0 +1,8 @@
type ifaa_app, domain, coredomain;
app_domain(ifaa_app)
hal_client_domain(ifaa_app, vendor_hal_fingerprintpay)
allow ifaa_app app_api_service:service_manager find;
get_prop(ifaa_app, system_fingerprint_prop)

View File

@@ -36,6 +36,9 @@ oplus.fingerprint. u:object_r:system_fingerprint_prop:s0
oplus.goodix.fp u:object_r:system_fingerprint_prop:s0
oplus.optical. u:object_r:system_fingerprint_prop:s0
persist.sys.fp. u:object_r:system_fingerprint_prop:s0
persist.vendor.fingerprint.optical.iconlocation u:object_r:system_fingerprint_prop:s0
persist.vendor.fingerprint.optical.iconsize u:object_r:system_fingerprint_prop:s0
persist.vendor.fingerprint.sensor_type u:object_r:system_fingerprint_prop:s0
# Logging
aec.custom.debug. u:object_r:exported_system_prop:s0

View File

@@ -1 +1,2 @@
user=_app seinfo=platform name=org.ifaa.aidl.manager domain=ifaa_app type=app_data_file levelFrom=user
user=_app seinfo=platform name=org.lineageos.pen domain=pen_app type=app_data_file levelFrom=user

View File

@@ -2,7 +2,7 @@
vendor_internal_prop(system_oplus_iris_prop)
# Fingerprint
vendor_internal_prop(system_fingerprint_prop)
vendor_restricted_prop(system_fingerprint_prop)
# Radio
system_public_prop(system_oplus_radio_prop)