Michael Marshall
07/23/2023, 11:59 PMContinuation
parameter of a suspend
function would ever not be the last parameter of the function? The documentation doesn’t say explicitly it has to be the last parameter but some articles I’ve read have said that it always is. We seem to have found a case where it isn’t the last parameter in our own codebase, but we’re not sure why that would happen.Chris Lee
07/24/2023, 12:25 AMMichael Marshall
07/24/2023, 1:23 AMsuspend
functions only, and have been applying it on a bunch of interfaces. However on a specific function on a specific interface the proxy wasn’t working, but only on release builds. It appears that ProGuard may be rearranging the order of the parameters perhaps, rather than the compiler?
Here’s the basic proxy
private class MyProxy<Interface>(
private val interface: Interface,
) : InvocationHandler {
override fun invoke(proxy: Any, method: Method, args: Array<out Any>?): Any? {
val nonNullArgs = args.orEmpty()
val lastArgument = nonNullArgs.lastOrNull()
// If the method is not suspending just invoke it as normal.
if (lastArgument !is Continuation<*>) {
return method.invoke(interface, *nonNullArgs)
}
// Do proxy things on suspend function here
}
}
Chris Lee
07/24/2023, 1:28 AMMichael Marshall
07/24/2023, 1:37 AMInvocationHandler
class is Java and is not Kotlin-aware, so we can’t directly check for suspending functions. I’ve just found this on the web which we could make use of instead https://github.com/shaun-wild/KProxy
Good idea to check the bytecode, that’ll be my next stepMichael Marshall
07/24/2023, 6:13 AMsuspend fun myFunc(
myString: String,
myBool: Boolean,
): MyReturnType
When decompiled, a Continuation
object is added at the end.
public Object myFunc(@NotNull String myString, @Nullable boolean myBool, @NotNull Continuation var3)
However, once minified, the method parameters’ order changes to myString
, Continuation
, myBool
.
We confirmed this behaviour by making myString
nullable (myString: Boolean?
). Doing so forced the Kotlin compiler to decompile it into a Java Boolean
object, thereby maintaining the correct order of parameters.
public Object myFunc(@NotNull String myString, @Nullable Boolean myBool, @NotNull Continuation var3)
Michael Marshall
07/24/2023, 6:16 AM-keep,allowobfuscation, allowshrinking class * implements com.example.MyProxy { *; }