瀏覽代碼

Destroy stale channels properly

Peter Cai 3 年之前
父節點
當前提交
6451e0a0d6

+ 7 - 1
app/src/main/java/im/angry/openeuicc/core/EuiccChannel.kt

@@ -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
 )

+ 19 - 8
app/src/main/java/im/angry/openeuicc/core/EuiccChannelManager.kt

@@ -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

+ 10 - 2
app/src/main/java/im/angry/openeuicc/core/OmapiApduChannel.kt

@@ -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))