Destroy stale channels properly

This commit is contained in:
Peter Cai 2022-05-02 15:25:55 -04:00
parent c78743f03f
commit 6451e0a0d6
3 changed files with 36 additions and 11 deletions

View File

@ -2,8 +2,14 @@ package im.angry.openeuicc.core
import com.truphone.lpa.LocalProfileAssistant
interface EuiccChannelStateManager {
val valid: Boolean
fun destroy()
}
data class EuiccChannel(
val slotId: Int,
val name: String,
val lpa: LocalProfileAssistant
val lpa: LocalProfileAssistant,
val stateManager: EuiccChannelStateManager
)

View File

@ -41,16 +41,23 @@ class EuiccChannelManager(private val context: Context) {
private suspend fun findEuiccChannelBySlot(slotId: Int): EuiccChannel? {
ensureSEService()
val existing = channels.find { it.slotId == slotId }
if (existing != null) return existing
var apduChannel: ApduChannel?
apduChannel = OmapiApduChannel.tryConnectUiccSlot(seService!!, slotId)
if (apduChannel == null) {
return null
if (existing != null) {
if (existing.stateManager.valid) {
return existing
} else {
existing.stateManager.destroy()
channels.remove(existing)
}
}
val channel = EuiccChannel(slotId, "SIM $slotId", LocalProfileAssistantImpl(apduChannel))
var apduChannel: ApduChannel? = null
var stateManager: EuiccChannelStateManager? = null
OmapiApduChannel.tryConnectUiccSlot(seService!!, slotId)?.let { (_apduChannel, _stateManager) ->
apduChannel = _apduChannel
stateManager = _stateManager
} ?: return null
val channel = EuiccChannel(slotId, "SIM $slotId", LocalProfileAssistantImpl(apduChannel), stateManager!!)
channels.add(channel)
return channel
}
@ -77,6 +84,10 @@ class EuiccChannelManager(private val context: Context) {
get() = channels.toList()
fun invalidate() {
for (channel in channels) {
channel.stateManager.destroy()
}
channels.clear()
seService?.shutdown()
seService = null

View File

@ -14,12 +14,20 @@ class OmapiApduChannel(private val channel: Channel) : ApduChannel {
private const val TAG = "OmapiApduChannel"
private val APPLET_ID = byteArrayOf(-96, 0, 0, 5, 89, 16, 16, -1, -1, -1, -1, -119, 0, 0, 1, 0)
fun tryConnectUiccSlot(service: SEService, slotId: Int): OmapiApduChannel? {
fun tryConnectUiccSlot(service: SEService, slotId: Int): Pair<ApduChannel, EuiccChannelStateManager>? {
try {
val reader = service.getUiccReader(slotId + 1) // slotId from telephony starts from 0
val session = reader.openSession()
val channel = session.openLogicalChannel(APPLET_ID) ?: return null
return OmapiApduChannel(channel)
val stateManager = object : EuiccChannelStateManager {
override val valid: Boolean
get() = channel.isOpen
override fun destroy() {
channel.close()
}
}
return Pair(OmapiApduChannel(channel), stateManager)
} catch (e: Exception) {
Log.e(TAG, "Unable to open eUICC channel for slot ${slotId}, skipping")
Log.e(TAG, Log.getStackTraceString(e))