Compare commits

..

3 commits

Author SHA1 Message Date
21c04ed179 Allow Actions to build from any branch 2025-06-17 07:57:19 -04:00
db4645b17f feat: sas accreditation number format check (#193)
Reviewed-on: PeterCxy/OpenEUICC#193
Co-authored-by: septs <github@septs.pw>
Co-committed-by: septs <github@septs.pw>
2025-06-16 03:54:32 +02:00
149a19ca1c fix: build warning (#194)
Reviewed-on: PeterCxy/OpenEUICC#194
Co-authored-by: xqdoo00o <xqdoo00o@gmail.com>
Co-committed-by: xqdoo00o <xqdoo00o@gmail.com>
2025-06-16 03:54:02 +02:00
11 changed files with 65 additions and 85 deletions

View file

@ -1,7 +1,7 @@
on: on:
push: push:
branches: branches:
- 'master' - '*'
jobs: jobs:
build-debug: build-debug:

View file

@ -20,8 +20,7 @@ open class DefaultEuiccChannelFactory(protected val context: Context) : EuiccCha
override suspend fun tryOpenEuiccChannel( override suspend fun tryOpenEuiccChannel(
port: UiccPortInfoCompat, port: UiccPortInfoCompat,
isdrAid: ByteArray, isdrAid: ByteArray
seId: Int,
): EuiccChannel? { ): EuiccChannel? {
if (port.portIndex != 0) { if (port.portIndex != 0) {
Log.w( Log.w(
@ -47,7 +46,6 @@ open class DefaultEuiccChannelFactory(protected val context: Context) : EuiccCha
context.preferenceRepository.verboseLoggingFlow context.preferenceRepository.verboseLoggingFlow
), ),
isdrAid, isdrAid,
seId,
context.preferenceRepository.verboseLoggingFlow, context.preferenceRepository.verboseLoggingFlow,
context.preferenceRepository.ignoreTLSCertificateFlow, context.preferenceRepository.ignoreTLSCertificateFlow,
).also { ).also {
@ -67,8 +65,7 @@ open class DefaultEuiccChannelFactory(protected val context: Context) : EuiccCha
override fun tryOpenUsbEuiccChannel( override fun tryOpenUsbEuiccChannel(
ccidCtx: UsbCcidContext, ccidCtx: UsbCcidContext,
isdrAid: ByteArray, isdrAid: ByteArray
seId: Int
): EuiccChannel? { ): EuiccChannel? {
try { try {
return EuiccChannelImpl( return EuiccChannelImpl(
@ -79,7 +76,6 @@ open class DefaultEuiccChannelFactory(protected val context: Context) : EuiccCha
ccidCtx ccidCtx
), ),
isdrAid, isdrAid,
seId,
context.preferenceRepository.verboseLoggingFlow, context.preferenceRepository.verboseLoggingFlow,
context.preferenceRepository.ignoreTLSCertificateFlow, context.preferenceRepository.ignoreTLSCertificateFlow,
) )

View file

@ -32,7 +32,7 @@ open class DefaultEuiccChannelManager(
private val channelCache = mutableListOf<EuiccChannel>() private val channelCache = mutableListOf<EuiccChannel>()
private var usbChannels = mutableListOf<EuiccChannel>() private var usbChannel: EuiccChannel? = null
private val lock = Mutex() private val lock = Mutex()
@ -51,17 +51,15 @@ open class DefaultEuiccChannelManager(
protected open val uiccCards: Collection<UiccCardInfoCompat> protected open val uiccCards: Collection<UiccCardInfoCompat>
get() = (0..<tm.activeModemCountCompat).map { FakeUiccCardInfoCompat(it) } get() = (0..<tm.activeModemCountCompat).map { FakeUiccCardInfoCompat(it) }
private suspend inline fun tryOpenChannelWithKnownAids(openFn: (ByteArray, Int) -> EuiccChannel?): List<EuiccChannel> { private suspend inline fun tryOpenChannelFirstValidAid(openFn: (ByteArray) -> EuiccChannel?): EuiccChannel? {
val isdrAidList = val isdrAidList =
parseIsdrAidList(appContainer.preferenceRepository.isdrAidListFlow.first()) parseIsdrAidList(appContainer.preferenceRepository.isdrAidListFlow.first())
var seId = 0
return isdrAidList.mapNotNull { return isdrAidList.firstNotNullOfOrNull {
Log.i(TAG, "Opening channel, trying ISDR AID ${it.encodeHex()}, this will be seId ${seId}") Log.i(TAG, "Opening channel, trying ISDR AID ${it.encodeHex()}")
openFn(it, seId)?.let { channel -> openFn(it)?.let { channel ->
if (channel.valid) { if (channel.valid) {
seId += 1
channel channel
} else { } else {
channel.close() channel.close()
@ -71,15 +69,19 @@ open class DefaultEuiccChannelManager(
} }
} }
private suspend fun tryOpenEuiccChannel(port: UiccPortInfoCompat, seId: Int = 0): EuiccChannel? { private suspend fun tryOpenEuiccChannel(port: UiccPortInfoCompat): EuiccChannel? {
lock.withLock { lock.withLock {
if (port.card.physicalSlotIndex == EuiccChannelManager.USB_CHANNEL_ID) { if (port.card.physicalSlotIndex == EuiccChannelManager.USB_CHANNEL_ID) {
// We only compare seId because we assume we can only open 1 card from USB return if (usbChannel != null && usbChannel!!.valid) {
return usbChannels.find { it.seId == seId } usbChannel
} else {
usbChannel = null
null
}
} }
val existing = val existing =
channelCache.find { it.slotId == port.card.physicalSlotIndex && it.portId == port.portIndex && it.seId == seId } channelCache.find { it.slotId == port.card.physicalSlotIndex && it.portId == port.portIndex }
if (existing != null) { if (existing != null) {
if (existing.valid && port.logicalSlotIndex == existing.logicalSlotId) { if (existing.valid && port.logicalSlotIndex == existing.logicalSlotId) {
return existing return existing
@ -94,12 +96,12 @@ open class DefaultEuiccChannelManager(
return null return null
} }
val channels = val channel =
tryOpenChannelWithKnownAids { isdrAid, seId -> euiccChannelFactory.tryOpenEuiccChannel(port, isdrAid, seId) } tryOpenChannelFirstValidAid { euiccChannelFactory.tryOpenEuiccChannel(port, it) }
if (channels.isNotEmpty()) { if (channel != null) {
channelCache.addAll(channels) channelCache.add(channel)
return channels.find { it.seId == seId } return channel
} else { } else {
Log.i( Log.i(
TAG, TAG,
@ -110,10 +112,10 @@ open class DefaultEuiccChannelManager(
} }
} }
protected suspend fun findEuiccChannelByLogicalSlot(logicalSlotId: Int, seId: Int = 0): EuiccChannel? = protected suspend fun findEuiccChannelByLogicalSlot(logicalSlotId: Int): EuiccChannel? =
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
if (logicalSlotId == EuiccChannelManager.USB_CHANNEL_ID) { if (logicalSlotId == EuiccChannelManager.USB_CHANNEL_ID) {
return@withContext usbChannels.find { it.seId == seId } return@withContext usbChannel
} }
for (card in uiccCards) { for (card in uiccCards) {
@ -129,7 +131,7 @@ open class DefaultEuiccChannelManager(
private suspend fun findAllEuiccChannelsByPhysicalSlot(physicalSlotId: Int): List<EuiccChannel>? { private suspend fun findAllEuiccChannelsByPhysicalSlot(physicalSlotId: Int): List<EuiccChannel>? {
if (physicalSlotId == EuiccChannelManager.USB_CHANNEL_ID) { if (physicalSlotId == EuiccChannelManager.USB_CHANNEL_ID) {
return usbChannels.ifEmpty { null } return usbChannel?.let { listOf(it) }
} }
for (card in uiccCards) { for (card in uiccCards) {
@ -140,14 +142,14 @@ open class DefaultEuiccChannelManager(
return null return null
} }
private suspend fun findEuiccChannelByPort(physicalSlotId: Int, portId: Int, seId: Int = 0): EuiccChannel? = private suspend fun findEuiccChannelByPort(physicalSlotId: Int, portId: Int): EuiccChannel? =
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
if (physicalSlotId == EuiccChannelManager.USB_CHANNEL_ID) { if (physicalSlotId == EuiccChannelManager.USB_CHANNEL_ID) {
return@withContext usbChannels.find { it.seId == seId } return@withContext usbChannel
} }
uiccCards.find { it.physicalSlotIndex == physicalSlotId }?.let { card -> uiccCards.find { it.physicalSlotIndex == physicalSlotId }?.let { card ->
card.ports.find { it.portIndex == portId }?.let { tryOpenEuiccChannel(it, seId) } card.ports.find { it.portIndex == portId }?.let { tryOpenEuiccChannel(it) }
} }
} }
@ -166,16 +168,15 @@ open class DefaultEuiccChannelManager(
return@withContext listOf(0) return@withContext listOf(0)
} }
findAllEuiccChannelsByPhysicalSlot(physicalSlotId)?.map { it.portId }?.toSet()?.toList() ?: listOf() findAllEuiccChannelsByPhysicalSlot(physicalSlotId)?.map { it.portId } ?: listOf()
} }
override suspend fun <R> withEuiccChannel( override suspend fun <R> withEuiccChannel(
physicalSlotId: Int, physicalSlotId: Int,
portId: Int, portId: Int,
seId: Int,
fn: suspend (EuiccChannel) -> R fn: suspend (EuiccChannel) -> R
): R { ): R {
val channel = findEuiccChannelByPort(physicalSlotId, portId, seId) val channel = findEuiccChannelByPort(physicalSlotId, portId)
?: throw EuiccChannelManager.EuiccChannelNotFoundException() ?: throw EuiccChannelManager.EuiccChannelNotFoundException()
val wrapper = EuiccChannelWrapper(channel) val wrapper = EuiccChannelWrapper(channel)
try { try {
@ -189,10 +190,9 @@ open class DefaultEuiccChannelManager(
override suspend fun <R> withEuiccChannel( override suspend fun <R> withEuiccChannel(
logicalSlotId: Int, logicalSlotId: Int,
seId: Int,
fn: suspend (EuiccChannel) -> R fn: suspend (EuiccChannel) -> R
): R { ): R {
val channel = findEuiccChannelByLogicalSlot(logicalSlotId, seId) val channel = findEuiccChannelByLogicalSlot(logicalSlotId)
?: throw EuiccChannelManager.EuiccChannelNotFoundException() ?: throw EuiccChannelManager.EuiccChannelNotFoundException()
val wrapper = EuiccChannelWrapper(channel) val wrapper = EuiccChannelWrapper(channel)
try { try {
@ -206,8 +206,8 @@ open class DefaultEuiccChannelManager(
override suspend fun waitForReconnect(physicalSlotId: Int, portId: Int, timeoutMillis: Long) { override suspend fun waitForReconnect(physicalSlotId: Int, portId: Int, timeoutMillis: Long) {
if (physicalSlotId == EuiccChannelManager.USB_CHANNEL_ID) { if (physicalSlotId == EuiccChannelManager.USB_CHANNEL_ID) {
usbChannels.forEach { it.close() } usbChannel?.close()
usbChannels.clear() usbChannel = null
} else { } else {
// If there is already a valid channel, we close it proactively // If there is already a valid channel, we close it proactively
// Sometimes the current channel can linger on for a bit even after it should have become invalid // Sometimes the current channel can linger on for a bit even after it should have become invalid
@ -223,7 +223,7 @@ open class DefaultEuiccChannelManager(
// tryOpenUsbEuiccChannel() will always try to reopen the channel, even if // tryOpenUsbEuiccChannel() will always try to reopen the channel, even if
// a USB channel already exists // a USB channel already exists
tryOpenUsbEuiccChannel() tryOpenUsbEuiccChannel()
usbChannels.getOrNull(0)!! usbChannel!!
} else { } else {
// tryOpenEuiccChannel() will automatically dispose of invalid channels // tryOpenEuiccChannel() will automatically dispose of invalid channels
// and recreate when needed // and recreate when needed
@ -280,13 +280,12 @@ open class DefaultEuiccChannelManager(
val ccidCtx = UsbCcidContext.createFromUsbDevice(context, device, iface) ?: return@forEach val ccidCtx = UsbCcidContext.createFromUsbDevice(context, device, iface) ?: return@forEach
try { try {
val channels = tryOpenChannelWithKnownAids { isdrAid, seId -> val channel = tryOpenChannelFirstValidAid {
euiccChannelFactory.tryOpenUsbEuiccChannel(ccidCtx, isdrAid, seId) euiccChannelFactory.tryOpenUsbEuiccChannel(ccidCtx, it)
} }
if (channels.isNotEmpty() && channels[0].valid) { if (channel != null && channel.lpa.valid) {
ccidCtx.allowDisconnect = true ccidCtx.allowDisconnect = true
usbChannels.clear() usbChannel = channel
usbChannels.addAll(channels)
return@withContext Pair(device, true) return@withContext Pair(device, true)
} }
} catch (e: Exception) { } catch (e: Exception) {
@ -310,8 +309,8 @@ open class DefaultEuiccChannelManager(
channel.close() channel.close()
} }
usbChannels.forEach { it.close() } usbChannel?.close()
usbChannels.clear() usbChannel = null
channelCache.clear() channelCache.clear()
euiccChannelFactory.cleanup() euiccChannelFactory.cleanup()
} }

View file

@ -13,16 +13,6 @@ interface EuiccChannel {
val logicalSlotId: Int val logicalSlotId: Int
val portId: Int val portId: Int
/**
* Some chips support multiple SEs on one chip. The seId here is intended
* to distinguish channels opened from these different SEs.
*
* Note that this ID is arbitrary and heavily depends on the order in which
* we attempt to open the ISD-R AIDs. As such, it shall not be treated with
* any significance other than as a transient ID.
*/
val seId: Int
val lpa: LocalProfileAssistant val lpa: LocalProfileAssistant
val valid: Boolean val valid: Boolean

View file

@ -6,12 +6,11 @@ import im.angry.openeuicc.util.*
// This class is here instead of inside DI because it contains a bit more logic than just // This class is here instead of inside DI because it contains a bit more logic than just
// "dumb" dependency injection. // "dumb" dependency injection.
interface EuiccChannelFactory { interface EuiccChannelFactory {
suspend fun tryOpenEuiccChannel(port: UiccPortInfoCompat, isdrAid: ByteArray, seInt: Int): EuiccChannel? suspend fun tryOpenEuiccChannel(port: UiccPortInfoCompat, isdrAid: ByteArray): EuiccChannel?
fun tryOpenUsbEuiccChannel( fun tryOpenUsbEuiccChannel(
ccidCtx: UsbCcidContext, ccidCtx: UsbCcidContext,
isdrAid: ByteArray, isdrAid: ByteArray
seInt: Int
): EuiccChannel? ): EuiccChannel?
/** /**

View file

@ -14,7 +14,6 @@ class EuiccChannelImpl(
override val intrinsicChannelName: String?, override val intrinsicChannelName: String?,
override val apduInterface: ApduInterface, override val apduInterface: ApduInterface,
override val isdrAid: ByteArray, override val isdrAid: ByteArray,
override val seId: Int,
verboseLoggingFlow: Flow<Boolean>, verboseLoggingFlow: Flow<Boolean>,
ignoreTLSCertificateFlow: Flow<Boolean> ignoreTLSCertificateFlow: Flow<Boolean>
) : EuiccChannel { ) : EuiccChannel {

View file

@ -81,7 +81,6 @@ interface EuiccChannelManager {
suspend fun <R> withEuiccChannel( suspend fun <R> withEuiccChannel(
physicalSlotId: Int, physicalSlotId: Int,
portId: Int, portId: Int,
seId: Int = 0,
fn: suspend (EuiccChannel) -> R fn: suspend (EuiccChannel) -> R
): R ): R
@ -90,7 +89,6 @@ interface EuiccChannelManager {
*/ */
suspend fun <R> withEuiccChannel( suspend fun <R> withEuiccChannel(
logicalSlotId: Int, logicalSlotId: Int,
seId: Int = 0,
fn: suspend (EuiccChannel) -> R fn: suspend (EuiccChannel) -> R
): R ): R

View file

@ -26,8 +26,6 @@ class EuiccChannelWrapper(orig: EuiccChannel) : EuiccChannel {
get() = channel.logicalSlotId get() = channel.logicalSlotId
override val portId: Int override val portId: Int
get() = channel.portId get() = channel.portId
override val seId: Int
get() = channel.seId
private val lpaDelegate = lazy { private val lpaDelegate = lazy {
LocalProfileAssistantWrapper(channel.lpa) LocalProfileAssistantWrapper(channel.lpa)
} }

View file

@ -27,6 +27,13 @@ import kotlinx.coroutines.launch
import net.typeblog.lpac_jni.impl.PKID_GSMA_LIVE_CI import net.typeblog.lpac_jni.impl.PKID_GSMA_LIVE_CI
import net.typeblog.lpac_jni.impl.PKID_GSMA_TEST_CI import net.typeblog.lpac_jni.impl.PKID_GSMA_TEST_CI
// https://euicc-manual.osmocom.org/docs/pki/eum/accredited.json
// ref: <https://regex101.com/r/5FFz8u>
private val RE_SAS = Regex(
"""^[A-Z]{2}-[A-Z]{2}(?:-UP)?-\d{4}T?(?:-\d+)?T?$""",
setOf(RegexOption.IGNORE_CASE),
)
class EuiccInfoActivity : BaseEuiccAccessActivity(), OpenEuiccContextMarker { class EuiccInfoActivity : BaseEuiccAccessActivity(), OpenEuiccContextMarker {
companion object { companion object {
private val YES_NO = Pair(R.string.yes, R.string.no) private val YES_NO = Pair(R.string.yes, R.string.no)
@ -92,7 +99,7 @@ class EuiccInfoActivity : BaseEuiccAccessActivity(), OpenEuiccContextMarker {
lifecycleScope.launch { lifecycleScope.launch {
(infoList.adapter!! as EuiccInfoAdapter).euiccInfoItems = (infoList.adapter!! as EuiccInfoAdapter).euiccInfoItems =
euiccChannelManager.withEuiccChannel(logicalSlotId, fn = ::buildEuiccInfoItems) euiccChannelManager.withEuiccChannel(logicalSlotId, ::buildEuiccInfoItems)
swipeRefresh.isRefreshing = false swipeRefresh.isRefreshing = false
} }
@ -109,13 +116,14 @@ class EuiccInfoActivity : BaseEuiccAccessActivity(), OpenEuiccContextMarker {
vendorInfo.firmwareVersion?.let { add(Item(R.string.euicc_info_fw_ver, it)) } vendorInfo.firmwareVersion?.let { add(Item(R.string.euicc_info_fw_ver, it)) }
vendorInfo.bootloaderVersion?.let { add(Item(R.string.euicc_info_bl_ver, it)) } vendorInfo.bootloaderVersion?.let { add(Item(R.string.euicc_info_bl_ver, it)) }
} }
channel.lpa.euiccInfo2.let { info -> channel.lpa.euiccInfo2?.let { info ->
add(Item(R.string.euicc_info_sgp22_version, info?.sgp22Version.toString())) add(Item(R.string.euicc_info_sgp22_version, info.sgp22Version.toString()))
add(Item(R.string.euicc_info_firmware_version, info?.euiccFirmwareVersion.toString())) add(Item(R.string.euicc_info_firmware_version, info.euiccFirmwareVersion.toString()))
add(Item(R.string.euicc_info_globalplatform_version, info?.globalPlatformVersion.toString())) add(Item(R.string.euicc_info_globalplatform_version, info.globalPlatformVersion.toString()))
add(Item(R.string.euicc_info_pp_version, info?.ppVersion.toString())) add(Item(R.string.euicc_info_pp_version, info.ppVersion.toString()))
add(Item(R.string.euicc_info_sas_accreditation_number, info?.sasAccreditationNumber)) info.sasAccreditationNumber.trim().takeIf(RE_SAS::matches)
add(Item(R.string.euicc_info_free_nvram, info?.freeNvram?.let(::formatFreeSpace))) ?.let { add(Item(R.string.euicc_info_sas_accreditation_number, it.uppercase())) }
add(Item(R.string.euicc_info_free_nvram, info.freeNvram.let(::formatFreeSpace)))
} }
channel.lpa.euiccInfo2?.euiccCiPKIdListForSigning.orEmpty().let { signers -> channel.lpa.euiccInfo2?.euiccCiPKIdListForSigning.orEmpty().let { signers ->
// SGP.28 v1.0, eSIM CI Registration Criteria (Page 5 of 9, 2019-10-24) // SGP.28 v1.0, eSIM CI Registration Criteria (Page 5 of 9, 2019-10-24)
@ -130,18 +138,13 @@ class EuiccInfoActivity : BaseEuiccAccessActivity(), OpenEuiccContextMarker {
} }
add(Item(R.string.euicc_info_ci_type, getString(resId))) add(Item(R.string.euicc_info_ci_type, getString(resId)))
} }
val atr = channel.atr?.encodeHex() ?: getString(R.string.information_unavailable) val atr = channel.atr?.encodeHex() ?: getString(R.string.information_unavailable)
add(Item(R.string.euicc_info_atr, atr, copiedToastResId = R.string.toast_atr_copied)) add(Item(R.string.euicc_info_atr, atr, copiedToastResId = R.string.toast_atr_copied))
} }
@Suppress("SameParameterValue")
private fun formatByBoolean(b: Boolean, res: Pair<Int, Int>): String = private fun formatByBoolean(b: Boolean, res: Pair<Int, Int>): String =
getString( getString(if (b) res.first else res.second)
if (b) {
res.first
} else {
res.second
}
)
inner class EuiccInfoViewHolder(root: View) : ViewHolder(root) { inner class EuiccInfoViewHolder(root: View) : ViewHolder(root) {
private val title: TextView = root.requireViewById(R.id.euicc_info_title) private val title: TextView = root.requireViewById(R.id.euicc_info_title)

View file

@ -16,14 +16,13 @@ class PrivilegedEuiccChannelFactory(context: Context) : DefaultEuiccChannelFacto
@Suppress("NAME_SHADOWING") @Suppress("NAME_SHADOWING")
override suspend fun tryOpenEuiccChannel( override suspend fun tryOpenEuiccChannel(
port: UiccPortInfoCompat, port: UiccPortInfoCompat,
isdrAid: ByteArray, isdrAid: ByteArray
seId: Int,
): EuiccChannel? { ): EuiccChannel? {
val port = port as RealUiccPortInfoCompat val port = port as RealUiccPortInfoCompat
if (port.card.isRemovable) { if (port.card.isRemovable) {
// Attempt unprivileged (OMAPI) before TelephonyManager // Attempt unprivileged (OMAPI) before TelephonyManager
// but still try TelephonyManager in case OMAPI is broken // but still try TelephonyManager in case OMAPI is broken
super.tryOpenEuiccChannel(port, isdrAid, seId)?.let { return it } super.tryOpenEuiccChannel(port, isdrAid)?.let { return it }
} }
if (port.card.isEuicc || preferenceRepository.removableTelephonyManagerFlow.first()) { if (port.card.isEuicc || preferenceRepository.removableTelephonyManagerFlow.first()) {
@ -42,7 +41,6 @@ class PrivilegedEuiccChannelFactory(context: Context) : DefaultEuiccChannelFacto
context.preferenceRepository.verboseLoggingFlow context.preferenceRepository.verboseLoggingFlow
), ),
isdrAid, isdrAid,
seId,
context.preferenceRepository.verboseLoggingFlow, context.preferenceRepository.verboseLoggingFlow,
context.preferenceRepository.ignoreTLSCertificateFlow, context.preferenceRepository.ignoreTLSCertificateFlow,
) )
@ -55,6 +53,6 @@ class PrivilegedEuiccChannelFactory(context: Context) : DefaultEuiccChannelFacto
} }
} }
return super.tryOpenEuiccChannel(port, isdrAid, seId) return super.tryOpenEuiccChannel(port, isdrAid)
} }
} }

View file

@ -80,7 +80,7 @@ apdu_interface_transmit(struct euicc_ctx *ctx, uint8_t **rx, uint32_t *rx_len, c
LPAC_JNI_EXCEPTION_RETURN; LPAC_JNI_EXCEPTION_RETURN;
*rx_len = (*env)->GetArrayLength(env, ret); *rx_len = (*env)->GetArrayLength(env, ret);
*rx = calloc(*rx_len, sizeof(uint8_t)); *rx = calloc(*rx_len, sizeof(uint8_t));
(*env)->GetByteArrayRegion(env, ret, 0, *rx_len, *rx); (*env)->GetByteArrayRegion(env, ret, 0, *rx_len, (jbyte *) *rx);
(*env)->DeleteLocalRef(env, txArr); (*env)->DeleteLocalRef(env, txArr);
(*env)->DeleteLocalRef(env, ret); (*env)->DeleteLocalRef(env, ret);
return 0; return 0;
@ -113,7 +113,7 @@ http_interface_transmit(struct euicc_ctx *ctx, const char *url, uint32_t *rcode,
jbyteArray rxArr = (jbyteArray) (*env)->GetObjectField(env, ret, field_resp_data); jbyteArray rxArr = (jbyteArray) (*env)->GetObjectField(env, ret, field_resp_data);
*rx_len = (*env)->GetArrayLength(env, rxArr); *rx_len = (*env)->GetArrayLength(env, rxArr);
*rx = calloc(*rx_len, sizeof(uint8_t)); *rx = calloc(*rx_len, sizeof(uint8_t));
(*env)->GetByteArrayRegion(env, rxArr, 0, *rx_len, *rx); (*env)->GetByteArrayRegion(env, rxArr, 0, *rx_len, (jbyte *) *rx);
(*env)->DeleteLocalRef(env, txArr); (*env)->DeleteLocalRef(env, txArr);
(*env)->DeleteLocalRef(env, rxArr); (*env)->DeleteLocalRef(env, rxArr);
(*env)->DeleteLocalRef(env, headersArr); (*env)->DeleteLocalRef(env, headersArr);