Compare commits

...

2 commits

2 changed files with 67 additions and 4 deletions

View file

@ -3,6 +3,7 @@ package im.angry.openeuicc.util
import android.content.Context import android.content.Context
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.os.Build import android.os.Build
import android.se.omapi.Reader
import android.telephony.TelephonyManager import android.telephony.TelephonyManager
import im.angry.easyeuicc.R import im.angry.easyeuicc.R
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@ -13,6 +14,7 @@ fun getCompatibilityChecks(context: Context): List<CompatibilityCheck> =
listOf( listOf(
HasSystemFeaturesCheck(context), HasSystemFeaturesCheck(context),
OmapiConnCheck(context), OmapiConnCheck(context),
IsdrChannelAccessCheck(context),
KnownBrokenCheck(context) KnownBrokenCheck(context)
) )
@ -25,6 +27,12 @@ suspend fun List<CompatibilityCheck>.executeAll(callback: () -> Unit) = withCont
} }
} }
private val Reader.isSIM: Boolean
get() = name.startsWith("SIM")
private val Reader.slotIndex: Int
get() = (name.replace("SIM", "").toIntOrNull() ?: 1)
abstract class CompatibilityCheck(context: Context) { abstract class CompatibilityCheck(context: Context) {
enum class State { enum class State {
NOT_STARTED, NOT_STARTED,
@ -100,11 +108,13 @@ internal class OmapiConnCheck(private val context: Context): CompatibilityCheck(
} }
val tm = context.getSystemService(TelephonyManager::class.java) val tm = context.getSystemService(TelephonyManager::class.java)
val simReaders = seService.readers.filter { it.name.startsWith("SIM") } val simReaders = seService.readers.filter { it.isSIM }
if (simReaders.size < tm.activeModemCountCompat) { if (simReaders.isEmpty()) {
failureDescription = context.getString(R.string.compatibility_check_omapi_connectivity_fail)
return false
} else if (simReaders.size < tm.activeModemCountCompat) {
failureDescription = context.getString(R.string.compatibility_check_omapi_connectivity_fail_sim_number, failureDescription = context.getString(R.string.compatibility_check_omapi_connectivity_fail_sim_number,
simReaders.map { (it.name.replace("SIM", "").toIntOrNull() ?: 1) - 1 } simReaders.map { it.slotIndex }.joinToString(", "))
.joinToString(", "))
return false return false
} }
@ -112,6 +122,56 @@ internal class OmapiConnCheck(private val context: Context): CompatibilityCheck(
} }
} }
internal class IsdrChannelAccessCheck(private val context: Context): CompatibilityCheck(context) {
companion object {
val ISDR_AID = "A0000005591010FFFFFFFF8900000100".decodeHex()
}
override val title: String
get() = context.getString(R.string.compatibility_check_isdr_channel)
override val defaultDescription: String
get() = context.getString(R.string.compatibility_check_isdr_channel_desc)
override suspend fun doCheck(): Boolean {
val seService = connectSEService(context)
val (validSlotIds, result) = seService.readers.filter { it.isSIM }.map {
try {
it.openSession().openLogicalChannel(ISDR_AID)?.close()
Pair(it.slotIndex, true)
} catch (_: SecurityException) {
// Ignore; this is expected when everything works
// ref: https://android.googlesource.com/platform/frameworks/base/+/4fe64fb4712a99d5da9c9a0eb8fd5169b252e1e1/omapi/java/android/se/omapi/Session.java#305
// SecurityException is only thrown when Channel is constructed, which means everything else needs to succeed
Pair(it.slotIndex, true)
} catch (e: Exception) {
e.printStackTrace()
Pair(it.slotIndex, false)
}
}.fold(Pair(mutableListOf<Int>(), true)) { (ids, result), (id, ok) ->
if (!ok) {
Pair(ids, false)
} else {
Pair(ids.apply { add(id) }, result)
}
}
if (!result && validSlotIds.size > 0) {
if (!context.packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY_EUICC)) {
failureDescription = context.getString(
R.string.compatibility_check_isdr_channel_desc_partial_fail,
validSlotIds.joinToString(", ")
)
} else {
// If the device has embedded eSIMs, we can likely ignore the failure here;
// the OMAPI failure likely resulted from trying to access internal eSIMs.
return true
}
}
return result
}
}
internal class KnownBrokenCheck(private val context: Context): CompatibilityCheck(context) { internal class KnownBrokenCheck(private val context: Context): CompatibilityCheck(context) {
companion object { companion object {
val BROKEN_MANUFACTURERS = arrayOf("xiaomi") val BROKEN_MANUFACTURERS = arrayOf("xiaomi")

View file

@ -11,6 +11,9 @@
<string name="compatibility_check_omapi_connectivity_desc">Does your device allow access to Secure Elements on SIM cards via OMAPI?</string> <string name="compatibility_check_omapi_connectivity_desc">Does your device allow access to Secure Elements on SIM cards via OMAPI?</string>
<string name="compatibility_check_omapi_connectivity_fail">Unable to detect Secure Element readers for SIM cards via OMAPI.</string> <string name="compatibility_check_omapi_connectivity_fail">Unable to detect Secure Element readers for SIM cards via OMAPI.</string>
<string name="compatibility_check_omapi_connectivity_fail_sim_number">Only the following SIM slots are accessible via OMAPI: %s.</string> <string name="compatibility_check_omapi_connectivity_fail_sim_number">Only the following SIM slots are accessible via OMAPI: %s.</string>
<string name="compatibility_check_isdr_channel">ISD-R Channel Access</string>
<string name="compatibility_check_isdr_channel_desc">Does your device support opening an ISD-R (management) channel to eSIMs via OMAPI?</string>
<string name="compatibility_check_isdr_channel_desc_partial_fail">OMAPI access to ISD-R is only possible on the following SIM slots: %s.</string>
<string name="compatibility_check_known_broken">Known Broken?</string> <string name="compatibility_check_known_broken">Known Broken?</string>
<string name="compatibility_check_known_broken_desc">Making sure your device is not known to have bugs associated with removable eSIMs.</string> <string name="compatibility_check_known_broken_desc">Making sure your device is not known to have bugs associated with removable eSIMs.</string>
<string name="compatibility_check_known_broken_fail">Oops, your device is known to have bugs when accessing removable eSIMs. This does not necessarily mean that it will not work at all, but you will have to proceed with caution.</string> <string name="compatibility_check_known_broken_fail">Oops, your device is known to have bugs when accessing removable eSIMs. This does not necessarily mean that it will not work at all, but you will have to proceed with caution.</string>