mirror of
https://github.com/oplus-giulia-dev/android_hardware_oplus
synced 2025-11-03 21:35:37 +08:00
IFAAService: Wire up oplus fingerprint pay AIDL
Change-Id: Ibbac7e3c4d6591b712cbdcfb3eda955fbb78f8f3
This commit is contained in:
committed by
Bruno Martins
parent
6be8136317
commit
d3b35847b1
@@ -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",
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -5,45 +5,43 @@
|
||||
|
||||
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 -> {
|
||||
applicationContext.startActivity(
|
||||
@@ -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()
|
||||
} catch (e: Exception) {
|
||||
Log.e(LOG_TAG, "processCmdImpl: mlipay invoke_command failed", e)
|
||||
}
|
||||
|
||||
receiveBuffer
|
||||
override fun processCmd(param: ByteArray) = try {
|
||||
getFpPayService()?.ifaa_invoke_command(param)
|
||||
} catch (e: Exception) {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
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 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"
|
||||
}
|
||||
}
|
||||
|
||||
8
sepolicy/qti/private/ifaa_app.te
Normal file
8
sepolicy/qti/private/ifaa_app.te
Normal 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)
|
||||
@@ -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
|
||||
|
||||
# Fingerprint
|
||||
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
|
||||
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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user