mirror of
https://github.com/oplus-giulia-dev/android_hardware_oplus
synced 2025-11-04 05:45:34 +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
|
// 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",
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
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
|
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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user