diff --git a/app-common/src/main/java/im/angry/openeuicc/core/EuiccChannel.kt b/app-common/src/main/java/im/angry/openeuicc/core/EuiccChannel.kt index 597a70d..5f399ea 100644 --- a/app-common/src/main/java/im/angry/openeuicc/core/EuiccChannel.kt +++ b/app-common/src/main/java/im/angry/openeuicc/core/EuiccChannel.kt @@ -1,7 +1,6 @@ package im.angry.openeuicc.core import im.angry.openeuicc.util.* -import net.typeblog.lpac_jni.ApduInterface import net.typeblog.lpac_jni.LocalProfileAssistant interface EuiccChannel { @@ -29,10 +28,5 @@ interface EuiccChannel { */ val intrinsicChannelName: String? - /** - * The underlying APDU interface for this channel - */ - val apduInterface: ApduInterface - fun close() } \ No newline at end of file diff --git a/app-common/src/main/java/im/angry/openeuicc/core/EuiccChannelImpl.kt b/app-common/src/main/java/im/angry/openeuicc/core/EuiccChannelImpl.kt index a56b1cc..3da829a 100644 --- a/app-common/src/main/java/im/angry/openeuicc/core/EuiccChannelImpl.kt +++ b/app-common/src/main/java/im/angry/openeuicc/core/EuiccChannelImpl.kt @@ -1,7 +1,6 @@ package im.angry.openeuicc.core -import im.angry.openeuicc.util.UiccPortInfoCompat -import im.angry.openeuicc.util.decodeHex +import im.angry.openeuicc.util.* import kotlinx.coroutines.flow.Flow import net.typeblog.lpac_jni.ApduInterface import net.typeblog.lpac_jni.LocalProfileAssistant @@ -12,7 +11,7 @@ class EuiccChannelImpl( override val type: String, override val port: UiccPortInfoCompat, override val intrinsicChannelName: String?, - override val apduInterface: ApduInterface, + private val apduInterface: ApduInterface, verboseLoggingFlow: Flow, ignoreTLSCertificateFlow: Flow ) : EuiccChannel { diff --git a/app-common/src/main/java/im/angry/openeuicc/core/EuiccChannelWrapper.kt b/app-common/src/main/java/im/angry/openeuicc/core/EuiccChannelWrapper.kt index 09004d3..4204e82 100644 --- a/app-common/src/main/java/im/angry/openeuicc/core/EuiccChannelWrapper.kt +++ b/app-common/src/main/java/im/angry/openeuicc/core/EuiccChannelWrapper.kt @@ -1,7 +1,6 @@ package im.angry.openeuicc.core import im.angry.openeuicc.util.* -import net.typeblog.lpac_jni.ApduInterface import net.typeblog.lpac_jni.LocalProfileAssistant class EuiccChannelWrapper(orig: EuiccChannel) : EuiccChannel { @@ -34,8 +33,6 @@ class EuiccChannelWrapper(orig: EuiccChannel) : EuiccChannel { get() = channel.valid override val intrinsicChannelName: String? get() = channel.intrinsicChannelName - override val apduInterface: ApduInterface - get() = channel.apduInterface override val atr: ByteArray? get() = channel.atr diff --git a/app-common/src/main/java/im/angry/openeuicc/core/OmapiApduInterface.kt b/app-common/src/main/java/im/angry/openeuicc/core/OmapiApduInterface.kt index a6a5cf0..bbf8fdd 100644 --- a/app-common/src/main/java/im/angry/openeuicc/core/OmapiApduInterface.kt +++ b/app-common/src/main/java/im/angry/openeuicc/core/OmapiApduInterface.kt @@ -7,9 +7,9 @@ import android.util.Log import im.angry.openeuicc.util.* import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.first -import kotlinx.coroutines.flow.single import kotlinx.coroutines.runBlocking import net.typeblog.lpac_jni.ApduInterface +import java.util.concurrent.atomic.AtomicInteger class OmapiApduInterface( private val service: SEService, @@ -21,12 +21,8 @@ class OmapiApduInterface( } private lateinit var session: Session - private val channels = arrayOf( - null, - null, - null, - null, - ) + private val channels = mutableMapOf() + private val index = AtomicInteger(0) override val valid: Boolean get() = service.isConnected && (this::session.isInitialized && !session.isClosed) @@ -45,22 +41,23 @@ class OmapiApduInterface( override fun logicalChannelOpen(aid: ByteArray): Int { val channel = session.openLogicalChannel(aid) check(channel != null) { "Failed to open logical channel (${aid.encodeHex()})" } - val index = channels.indexOf(null) - check(index != -1) { "No free logical channel slots" } - synchronized(channels) { channels[index] = channel } - return index + val id = index.addAndGet(1) + channels[id] = channel + return id } override fun logicalChannelClose(handle: Int) { - val channel = channels.getOrNull(handle) + val channel = channels[handle] check(channel != null) { "Invalid logical channel handle $handle" } + channels.remove(handle) if (channel.isOpen) channel.close() - synchronized(channels) { channels[handle] = null } } override fun transmit(handle: Int, tx: ByteArray): ByteArray { - val channel = channels.getOrNull(handle) - check(channel != null) { "Invalid logical channel handle $handle" } + val channel = channels[handle] + check(channel != null) { + "Invalid logical channel handle $handle" + } if (runBlocking { verboseLoggingFlow.first() }) { Log.d(TAG, "OMAPI APDU: ${tx.encodeHex()}") diff --git a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/ApduInterface.kt b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/ApduInterface.kt index 3689363..ced7ff1 100644 --- a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/ApduInterface.kt +++ b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/ApduInterface.kt @@ -17,12 +17,18 @@ interface ApduInterface { */ val valid: Boolean - fun withLogicalChannel(aid: ByteArray, callback: ((ByteArray) -> ByteArray) -> T): T { + fun openChannel(aid: ByteArray, callback: (TransmitProvider) -> T): T { val handle = logicalChannelOpen(aid) return try { - callback { tx -> transmit(handle, tx) } + callback(object : TransmitProvider { + override fun transmit(tx: ByteArray) = transmit(handle, tx) + }) } finally { logicalChannelClose(handle) } } } + +interface TransmitProvider { + fun transmit(tx: ByteArray): ByteArray +} \ No newline at end of file diff --git a/libs/lpac-jni/src/main/jni/lpac-jni/interface-wrapper.c b/libs/lpac-jni/src/main/jni/lpac-jni/interface-wrapper.c index a61fc96..b51f6a8 100644 --- a/libs/lpac-jni/src/main/jni/lpac-jni/interface-wrapper.c +++ b/libs/lpac-jni/src/main/jni/lpac-jni/interface-wrapper.c @@ -53,23 +53,20 @@ apdu_interface_logical_channel_open(struct euicc_ctx *ctx, const uint8_t *aid, u jint ret = (*env)->CallIntMethod(env, LPAC_JNI_CTX(ctx)->apdu_interface, method_apdu_logical_channel_open, jbarr); LPAC_JNI_EXCEPTION_RETURN; - LPAC_JNI_CTX(ctx)->logical_channel_id = ret; return ret; } -static void apdu_interface_logical_channel_close(struct euicc_ctx *ctx, - __attribute__((unused)) uint8_t channel) { +static void apdu_interface_logical_channel_close(struct euicc_ctx *ctx, uint8_t channel) { LPAC_JNI_SETUP_ENV; - jint logical_channel_id = LPAC_JNI_CTX(ctx)->logical_channel_id; (*env)->CallVoidMethod(env, LPAC_JNI_CTX(ctx)->apdu_interface, - method_apdu_logical_channel_close, logical_channel_id); + method_apdu_logical_channel_close, channel); (*env)->ExceptionClear(env); } static int apdu_interface_transmit(struct euicc_ctx *ctx, uint8_t **rx, uint32_t *rx_len, const uint8_t *tx, uint32_t tx_len) { - const int logic_channel = LPAC_JNI_CTX(ctx)->logical_channel_id; + const int logic_channel = ctx->apdu._internal.logic_channel; LPAC_JNI_SETUP_ENV; jbyteArray txArr = (*env)->NewByteArray(env, tx_len); (*env)->SetByteArrayRegion(env, txArr, 0, tx_len, (const jbyte *) tx); diff --git a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.c b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.c index ca319db..6ea9d3e 100644 --- a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.c +++ b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.c @@ -28,7 +28,7 @@ jint JNI_OnLoad(JavaVM *vm, void *reserved) { string_constructor = (*env)->GetMethodID(env, string_class, "", "([BLjava/lang/String;)V"); - const jchar _unused[1]; + const char _unused[1]; empty_string = (*env)->NewString(env, _unused, 0); empty_string = (*env)->NewGlobalRef(env, empty_string); diff --git a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.h b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.h index c2300be..a5d6262 100644 --- a/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.h +++ b/libs/lpac-jni/src/main/jni/lpac-jni/lpac-jni.h @@ -8,7 +8,6 @@ _Static_assert(sizeof(void *) <= sizeof(jlong), "jlong must be big enough to hold a platform raw pointer"); struct lpac_jni_ctx { - jint logical_channel_id; jobject apdu_interface; jobject http_interface; };