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 // SPDX-License-Identifier: Apache-2.0
// //
@@ -15,8 +15,7 @@ android_app {
}, },
static_libs: [ static_libs: [
"android.hidl.base-V1.0-java", "vendor.oplus.hardware.biometrics.fingerprintpay-V1-java",
"vendor.xiaomi.hardware.mlipay-V1.1-java",
], ],
certificate: "platform", certificate: "platform",

View File

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

View File

@@ -5,45 +5,43 @@
package org.ifaa.aidl.manager package org.ifaa.aidl.manager
import android.app.KeyguardManager
import android.app.Service import android.app.Service
import android.content.Intent import android.content.Intent
import android.os.Build import android.graphics.Point
import android.os.IHwBinder import android.hardware.fingerprint.FingerprintManager
import android.os.IBinder
import android.os.ServiceManager
import android.os.SystemProperties import android.os.SystemProperties
import android.provider.Settings import android.provider.Settings
import android.util.Log import android.util.Log
import org.ifaa.aidl.manager.IfaaManagerService import android.view.WindowManager
import org.json.JSONObject import org.json.JSONObject
import vendor.xiaomi.hardware.mlipay.V1_1.IMlipayService import vendor.oplus.hardware.biometrics.fingerprintpay.IFingerprintPay
class IfaaService : Service() { class IfaaService : Service() {
private var _mlipayService: IMlipayService? = null private var _fpPayService: IFingerprintPay? = null
private val mlipayServiceDeathRecipient = IHwBinder.DeathRecipient { private val fpPayServiceDeathRecipient = IBinder.DeathRecipient {
Log.i(LOG_TAG, "mlipay service died") Log.i(LOG_TAG, "aidl FingerprintPay hal died, reset hal proxy!")
_mlipayService = null _fpPayService = null
} }
private val mBinder = object : IfaaManagerService.Stub() { private val fingerprintManager by lazy { getSystemService(FingerprintManager::class.java)!! }
override fun getSupportBIOTypes(): Int { private val keyguardManager by lazy { getSystemService(KeyguardManager::class.java)!! }
val fpVendor = SystemProperties.get(FP_VENDOR_PROP, "") private val windowManager by lazy { getSystemService(WindowManager::class.java)!! }
val isUdfps = SystemProperties.getBoolean(IS_UDFPS_PROP, false)
val supportedBioMask = when (!invalidFpVendors.contains(fpVendor.lowercase())) { override fun onBind(intent: Intent) = object : IfaaManagerService.Stub() {
true -> AUTH_TYPE_FINGERPRINT or AUTH_TYPE_IRIS private val _supportBIOTypes by lazy {
else -> AUTH_TYPE_IRIS 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) { override fun startBIOManager(authType: Int) = when (authType) {
AUTH_TYPE_FINGERPRINT -> { AUTH_TYPE_FINGERPRINT -> {
applicationContext.startActivity( applicationContext.startActivity(
@@ -58,126 +56,142 @@ class IfaaService : Service() {
else -> COMMAND_FAIL 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 -> override fun processCmd(param: ByteArray) = try {
var receiveBuffer: ByteArray? = null getFpPayService()?.ifaa_invoke_command(param)
} catch (e: Exception) {
val paramByteArray = ArrayList<Byte>().apply { Log.e(LOG_TAG, "processCmdImpl: ifaa_invoke_command aidl failed", e)
for (byte in param) { null
add(byte)
}
}
try {
val receiveBufferByteArray = mlipayService.invoke_command(
paramByteArray, paramByteArray.size
)
receiveBuffer = receiveBufferByteArray.toByteArray()
} catch (e: Exception) {
Log.e(LOG_TAG, "processCmdImpl: mlipay invoke_command failed", e)
}
receiveBuffer
} }
override fun getVersion() = 4 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) { override fun setExtInfo(authType: Int, keyExtInfo: String, valExtInfo: String) {
// Do nothing // Do nothing
} }
override fun getEnabled(bioType: Int) = when (bioType) { override fun getEnabled(bioType: Int): Int {
AUTH_TYPE_FINGERPRINT -> BIOMETRICS_AVAILABLE if (!keyguardManager.isKeyguardSecure) {
else -> SCREEN_LOCK_NONE Log.e(LOG_TAG, "No secure keyguard set.")
} return BIOMETRIC_NOUSE_NOSET_KEYGUARD
}
override fun getIDList(bioType: Int): IntArray { return when (bioType) {
var idList = IntArray(0) AUTH_TYPE_FINGERPRINT -> when {
!fingerprintManager.isHardwareDetected -> {
Log.e(LOG_TAG, "Fingerprint hardware not available!")
BIOMETRIC_NOUSE_SYSTEMLOCKED
}
getMlipayService()?.let { mlipayService -> fingerprintManager.enrolledFingerprints.isNullOrEmpty() -> {
try { Log.e(LOG_TAG, "Fingerprint not enrolled!")
val idListAL = mlipayService.ifaa_get_idlist(bioType) BIOMETRIC_NOUSE_NOT_ENROLLED
}
idList = idListAL.toIntArray() else -> BIOMETRIC_USE_READY
} catch (e: Exception) {
Log.e(LOG_TAG, "getIDListImpl: mlipay ifaa_get_idlist failed", e)
} }
else -> 0
}
}
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
} }
return idList else -> null
} }
} }
override fun onBind(intent: Intent) = mBinder private fun getFpPayService() = _fpPayService ?: run {
val binder = ServiceManager.getService("${IFingerprintPay.DESCRIPTOR}/default")
private fun getMlipayService() = _mlipayService ?: runCatching { IFingerprintPay.Stub.asInterface(binder)?.also {
IMlipayService.getService(true) binder.linkToDeath(fpPayServiceDeathRecipient, 0)
}.onSuccess { _fpPayService = it
_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 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 { companion object {
private val LOG_TAG = IfaaService::class.simpleName!! private val LOG_TAG = IfaaService::class.simpleName!!
private const val AUTH_TYPE_NOT_SUPPORT = 0 private const val AUTH_TYPE_NOT_SUPPORT = 0
private const val AUTH_TYPE_FINGERPRINT = 1 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(4).or(AUTH_TYPE_FINGERPRINT)
private const val AUTH_TYPE_OPTICAL_FINGERPRINT = 1.shl(2)
private const val BIOMETRICS_AVAILABLE = 1000 private const val BIOMETRIC_USE_READY = 1000
private const val SCREEN_LOCK_NONE = 1003 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_OK = 0
private const val COMMAND_FAIL = -1 private const val COMMAND_FAIL = -1
private const val SUPPORTED_BIO_MASK_PROP = "persist.vendor.sys.pay.ifaa" // Populated by fingerprint HAL
private const val FP_VENDOR_PROP = "persist.vendor.sys.fp.vendor" private const val FP_TYPE_PROP = "persist.vendor.fingerprint.sensor_type"
private const val IS_UDFPS_PROP = "ro.hardware.fp.udfps" private const val FP_ICON_SIZE_PROP = "persist.vendor.fingerprint.optical.iconsize"
private const val UDFPS_LOCATION_X_Y_PROP = "persist.vendor.sys.fp.udfps.location.X_Y" private const val FP_ICON_LOCATION_PROP = "persist.vendor.fingerprint.optical.iconlocation"
private const val UDFPS_SIZE_W_H_PROP = "persist.vendor.sys.fp.udfps.size.width_height"
private val invalidFpVendors = arrayOf( // NOTE: Populate ifaaModel from /my_stock/etc/sys_alipay_model_list.json
"", private const val IFAA_MODEL_PROP = "sys.oplus.ifaa.model"
"none",
) 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

@@ -32,10 +32,13 @@ ro.oplus.image.my_engineering.type u:object_r:exported_system_prop:s0
ro.sys.engineering.pre u:object_r:exported_system_prop:s0 ro.sys.engineering.pre u:object_r:exported_system_prop:s0
# Fingerprint # Fingerprint
oplus.fingerprint. u:object_r:system_fingerprint_prop:s0 oplus.fingerprint. u:object_r:system_fingerprint_prop:s0
oplus.goodix.fp 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 oplus.optical. u:object_r:system_fingerprint_prop:s0
persist.sys.fp. 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 # Logging
aec.custom.debug. u:object_r:exported_system_prop:s0 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 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) vendor_internal_prop(system_oplus_iris_prop)
# Fingerprint # Fingerprint
vendor_internal_prop(system_fingerprint_prop) vendor_restricted_prop(system_fingerprint_prop)
# Radio # Radio
system_public_prop(system_oplus_radio_prop) system_public_prop(system_oplus_radio_prop)