Hello everyone, I recently bumped into a weird run...
# coroutines
l
Hello everyone, I recently bumped into a weird runtime error when my Android app called a suspend function to perform an operation asynchronously. As I could not figure out the cause so far. I post the code snippet below and I am hoping to discuss it further here. Any comments are welcome. Thanks in advance.
Copy code
typealias AsyncCallback = (Result?, Throwable?) -> Unit
private val listeners = mutableListOf<Command>()

@ExperimentalUnsignedTypes
fun interface CommandInterface {
    fun performAsync(
        arg1: UByte,
        arg2: UByte?,
        arg3: ByteArray,
        callback: AsyncCallback
    )
}

@ExperimentalUnsignedTypes
data class Command(
    val arg1: UByte,
    val arg2: UByte? = null,
    val arg3: AsyncCallback
)


private val executor = CommandInterface { arg1, arg2, arg3, callback ->
        listeners.add(
            Command(
                arg1,
                arg2,
                callback = callback
            )
        )
        // This method returns [Result] and resume [continuation] 
        action(arg3)
    }

suspend fun perform(
        arg1: UByte,
        arg2: UByte?,
        arg3: ByteArray
    ): Result? =
        try {
                suspendCoroutineWithTimeout(10000) { continuation ->

                    try {
                        continuation.invokeOnCancellation {
                            cancelRequest(arg1, arg2)
                        }

                        //Log.d(TAG,"arg1 type : ${arg1 is UByte}")
                        executor.performAsync(
                            arg1,
                            arg2, 
                            arg3 = arg3
                        ) { result, exception ->
                            when {
                                response == null ->
                                    continuation.resumeWithException(Exception("Null point exception"))
                                exception != null ->
                                    continuation.resumeWithException(exception)
                                else -> {
                                    continuation.resume(result)
                                }
                            }
                        }
                    } catch (e: Throwable) {
                        e.message
                        continuation.cancel()
                    }
                }
            } catch (e: TimeoutCancellationException) {
                cancelRequest(arg1,arg2)
                null
            }
When the app called perform() function, it got an error in a coroutine:abstract method “void CommandInterface.performAsync-vmjznIo(byte, kotlin.UByte, byte[], kotlin.jvm.functions.Function2)” It seemed the Kotlin compiler recognised the first argument arg1 as byte, but the interface defined it as UByte. The Kotlin plugin I am using is 1.5.30, AGP version is 7.0.2
The issue could be invisible if I rebuilt the project many times or put one line e.g. Log.d() above the function entry where the error happened. The error message indicates the the arg1 in the interface implementation is compiled to a different data type --byte. As a result, JVM throws a runtime exception. But I can not figure out why an unsigned byte was converted at some point during the runtime. Is the unsigned data type considered to be unsafe in the coroutine library? OR is there a mismatch between Android coroutine library and Kotlin dependency libraries?
Changing the argument to Int seems fixing the issue.