mirror of
				https://github.com/oplus-giulia-dev/android_hardware_oplus
				synced 2025-11-04 13:55:35 +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"
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user