OpenEuiccService: Fix ServiceConnection leakage
All checks were successful
/ build-debug (push) Successful in 4m9s
All checks were successful
/ build-debug (push) Successful in 4m9s
This commit is contained in:
parent
1a1364f788
commit
083ee03f8e
1 changed files with 40 additions and 29 deletions
|
@ -13,7 +13,6 @@ import im.angry.openeuicc.core.EuiccChannel
|
|||
import im.angry.openeuicc.core.EuiccChannelManager
|
||||
import im.angry.openeuicc.util.*
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.single
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import java.lang.IllegalStateException
|
||||
|
||||
|
@ -57,8 +56,10 @@ class OpenEuiccService : EuiccService(), OpenEuiccContextMarker {
|
|||
*
|
||||
* This ensures that we only spawn and connect to APDU channels when we absolutely need to,
|
||||
* instead of keeping them open unnecessarily in the background at all times.
|
||||
*
|
||||
* This function cannot be inline because non-local returns may bypass the unbind
|
||||
*/
|
||||
private inline fun <T> withEuiccChannelManager(fn: EuiccChannelManagerContext.() -> T): T {
|
||||
private fun <T> withEuiccChannelManager(fn: EuiccChannelManagerContext.() -> T): T {
|
||||
val (binder, unbind) = runBlocking {
|
||||
bindServiceSuspended(
|
||||
Intent(
|
||||
|
@ -168,15 +169,20 @@ class OpenEuiccService : EuiccService(), OpenEuiccContextMarker {
|
|||
Log.i(TAG, "onGetEuiccProfileInfoList slotId=$slotId")
|
||||
if (slotId == -1 || shouldIgnoreSlot(slotId)) {
|
||||
Log.i(TAG, "ignoring slot $slotId")
|
||||
return GetEuiccProfileInfoListResult(RESULT_FIRST_USER, arrayOf(), true)
|
||||
return@withEuiccChannelManager GetEuiccProfileInfoListResult(
|
||||
RESULT_FIRST_USER,
|
||||
arrayOf(),
|
||||
true
|
||||
)
|
||||
}
|
||||
|
||||
// TODO: Temporarily enable the slot to access its profiles if it is currently unmapped
|
||||
val channel = findChannel(slotId) ?: return GetEuiccProfileInfoListResult(
|
||||
RESULT_FIRST_USER,
|
||||
arrayOf(),
|
||||
true
|
||||
)
|
||||
val channel =
|
||||
findChannel(slotId) ?: return@withEuiccChannelManager GetEuiccProfileInfoListResult(
|
||||
RESULT_FIRST_USER,
|
||||
arrayOf(),
|
||||
true
|
||||
)
|
||||
val profiles = channel.lpa.profiles.operational.map {
|
||||
EuiccProfileInfo.Builder(it.iccid).apply {
|
||||
setProfileName(it.name)
|
||||
|
@ -198,7 +204,11 @@ class OpenEuiccService : EuiccService(), OpenEuiccContextMarker {
|
|||
}.build()
|
||||
}
|
||||
|
||||
return GetEuiccProfileInfoListResult(RESULT_OK, profiles.toTypedArray(), channel.removable)
|
||||
return@withEuiccChannelManager GetEuiccProfileInfoListResult(
|
||||
RESULT_OK,
|
||||
profiles.toTypedArray(),
|
||||
channel.removable
|
||||
)
|
||||
}
|
||||
|
||||
override fun onGetEuiccInfo(slotId: Int): EuiccInfo {
|
||||
|
@ -207,30 +217,31 @@ class OpenEuiccService : EuiccService(), OpenEuiccContextMarker {
|
|||
|
||||
override fun onDeleteSubscription(slotId: Int, iccid: String): Int = withEuiccChannelManager {
|
||||
Log.i(TAG, "onDeleteSubscription slotId=$slotId iccid=$iccid")
|
||||
if (shouldIgnoreSlot(slotId)) return RESULT_FIRST_USER
|
||||
if (shouldIgnoreSlot(slotId)) return@withEuiccChannelManager RESULT_FIRST_USER
|
||||
|
||||
try {
|
||||
val channels = findAllChannels(slotId) ?: return RESULT_FIRST_USER
|
||||
val channels =
|
||||
findAllChannels(slotId) ?: return@withEuiccChannelManager RESULT_FIRST_USER
|
||||
|
||||
if (!channels[0].profileExists(iccid)) {
|
||||
return RESULT_FIRST_USER
|
||||
return@withEuiccChannelManager RESULT_FIRST_USER
|
||||
}
|
||||
|
||||
// If the profile is enabled by ANY channel (port), we cannot delete it
|
||||
channels.forEach { channel ->
|
||||
val profile = channel.lpa.profiles.find {
|
||||
it.iccid == iccid
|
||||
} ?: return RESULT_FIRST_USER
|
||||
} ?: return@withEuiccChannelManager RESULT_FIRST_USER
|
||||
|
||||
if (profile.state == LocalProfileInfo.State.Enabled) {
|
||||
// Must disable the profile first
|
||||
return RESULT_FIRST_USER
|
||||
return@withEuiccChannelManager RESULT_FIRST_USER
|
||||
}
|
||||
}
|
||||
|
||||
euiccChannelManager.beginTrackedOperationBlocking(channels[0].slotId, channels[0].portId) {
|
||||
if (channels[0].lpa.deleteProfile(iccid)) {
|
||||
return RESULT_OK
|
||||
return@withEuiccChannelManager RESULT_OK
|
||||
}
|
||||
|
||||
runBlocking {
|
||||
|
@ -238,9 +249,9 @@ class OpenEuiccService : EuiccService(), OpenEuiccContextMarker {
|
|||
}
|
||||
}
|
||||
|
||||
return RESULT_FIRST_USER
|
||||
return@withEuiccChannelManager RESULT_FIRST_USER
|
||||
} catch (e: Exception) {
|
||||
return RESULT_FIRST_USER
|
||||
return@withEuiccChannelManager RESULT_FIRST_USER
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -260,7 +271,7 @@ class OpenEuiccService : EuiccService(), OpenEuiccContextMarker {
|
|||
forceDeactivateSim: Boolean
|
||||
): Int = withEuiccChannelManager {
|
||||
Log.i(TAG,"onSwitchToSubscriptionWithPort slotId=$slotId portIndex=$portIndex iccid=$iccid forceDeactivateSim=$forceDeactivateSim")
|
||||
if (shouldIgnoreSlot(slotId)) return RESULT_FIRST_USER
|
||||
if (shouldIgnoreSlot(slotId)) return@withEuiccChannelManager RESULT_FIRST_USER
|
||||
|
||||
try {
|
||||
// retryWithTimeout is needed here because this function may be called just after
|
||||
|
@ -272,7 +283,7 @@ class OpenEuiccService : EuiccService(), OpenEuiccContextMarker {
|
|||
} ?: run {
|
||||
if (!forceDeactivateSim) {
|
||||
// The user must select which SIM to deactivate
|
||||
return@onSwitchToSubscriptionWithPort RESULT_MUST_DEACTIVATE_SIM
|
||||
return@withEuiccChannelManager RESULT_MUST_DEACTIVATE_SIM
|
||||
} else {
|
||||
try {
|
||||
// If we are allowed to deactivate any SIM we like, try mapping the indicated port first
|
||||
|
@ -282,13 +293,13 @@ class OpenEuiccService : EuiccService(), OpenEuiccContextMarker {
|
|||
// We cannot map the port (or it is already mapped)
|
||||
// but we can also use any port available on the card
|
||||
retryWithTimeout(5000) { findChannel(slotId) }
|
||||
} ?: return@onSwitchToSubscriptionWithPort RESULT_FIRST_USER
|
||||
} ?: return@withEuiccChannelManager RESULT_FIRST_USER
|
||||
}
|
||||
}
|
||||
|
||||
if (iccid != null && !channel.profileExists(iccid)) {
|
||||
Log.i(TAG, "onSwitchToSubscriptionWithPort iccid=$iccid not found")
|
||||
return RESULT_FIRST_USER
|
||||
return@withEuiccChannelManager RESULT_FIRST_USER
|
||||
}
|
||||
|
||||
euiccChannelManager.beginTrackedOperationBlocking(channel.slotId, channel.portId) {
|
||||
|
@ -296,11 +307,11 @@ class OpenEuiccService : EuiccService(), OpenEuiccContextMarker {
|
|||
// Disable any active profile first if present
|
||||
channel.lpa.disableActiveProfile(false)
|
||||
if (!channel.lpa.enableProfile(iccid)) {
|
||||
return RESULT_FIRST_USER
|
||||
return@withEuiccChannelManager RESULT_FIRST_USER
|
||||
}
|
||||
} else {
|
||||
if (!channel.lpa.disableActiveProfile(true)) {
|
||||
return RESULT_FIRST_USER
|
||||
return@withEuiccChannelManager RESULT_FIRST_USER
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -310,9 +321,9 @@ class OpenEuiccService : EuiccService(), OpenEuiccContextMarker {
|
|||
}
|
||||
}
|
||||
|
||||
return RESULT_OK
|
||||
return@withEuiccChannelManager RESULT_OK
|
||||
} catch (e: Exception) {
|
||||
return RESULT_FIRST_USER
|
||||
return@withEuiccChannelManager RESULT_FIRST_USER
|
||||
} finally {
|
||||
euiccChannelManager.invalidate()
|
||||
}
|
||||
|
@ -324,15 +335,15 @@ class OpenEuiccService : EuiccService(), OpenEuiccContextMarker {
|
|||
TAG,
|
||||
"onUpdateSubscriptionNickname slotId=$slotId iccid=$iccid nickname=$nickname"
|
||||
)
|
||||
if (shouldIgnoreSlot(slotId)) return RESULT_FIRST_USER
|
||||
val channel = findChannel(slotId) ?: return RESULT_FIRST_USER
|
||||
if (shouldIgnoreSlot(slotId)) return@withEuiccChannelManager RESULT_FIRST_USER
|
||||
val channel = findChannel(slotId) ?: return@withEuiccChannelManager RESULT_FIRST_USER
|
||||
if (!channel.profileExists(iccid)) {
|
||||
return RESULT_FIRST_USER
|
||||
return@withEuiccChannelManager RESULT_FIRST_USER
|
||||
}
|
||||
val success = channel.lpa
|
||||
.setNickname(iccid, nickname!!)
|
||||
appContainer.subscriptionManager.tryRefreshCachedEuiccInfo(channel.cardId)
|
||||
return if (success) {
|
||||
return@withEuiccChannelManager if (success) {
|
||||
RESULT_OK
|
||||
} else {
|
||||
RESULT_FIRST_USER
|
||||
|
|
Loading…
Add table
Reference in a new issue