JNIEnv problems / Binding limited to 16 parameter methods

GutembergRibeiroGutembergRibeiro BRMember
edited November 2014 in Xamarin.Android

Hi,

I'm trying to use a 3rd party .jar (with an embedded resource native library/JNI) on Xamrin Android. Currently looks like Xamarin.Android only support methods with less than 16 parameters and some of the methods on my .jar has more parameters than that, and when I'm using the binding project, it is generating the following warning at compile time, and don't generate the method on the C# class:

`Warning    17  More than 16 parameters were found, which goes beyond the maximum number of parameters, in managed type BR.Com.Gertec.Pinpad.PPC    C:\Sources\Pay Insight Platform\Development\PI - SDK\PI.SDK.Mobile.Gertec.Drivers.Droid\BINDINGSGENERATOR   PI.SDK.Mobile.Gertec.Drivers.Droid`

So, after try Xamarin support, without success, I've dig around and a mate suggested try use JNIEnv class in order to create an extension method for the class that was generated by the binding project so I came with this:

            public static class PPCBindingExtensions
            {
                static IntPtr id_ppc_GetEMVCard;
                public static void PPC_GetEMVCard(this PPC ppc, 
                          byte bTimeout,
                          byte bNetwork,
                          byte bAppType,
                          Java.Lang.String sIniAmount,
                          Java.Lang.String sDate,
                          Java.Lang.String sHour,
                          Java.Lang.String sTimeStamp,
                          Java.Util.Concurrent.Atomic.AtomicInteger aiCardType,
                          Java.Util.Concurrent.Atomic.AtomicInteger aiChipLastStatus,
                          Java.Util.Concurrent.Atomic.AtomicInteger aiAppTypeSelected,
                          Java.Util.Concurrent.Atomic.AtomicInteger aiNetworkSelected,
                          Java.Util.Concurrent.Atomic.AtomicInteger aiAIDIdx,
                          StringBuffer sTrk1,
                          StringBuffer sTrk2,
                          StringBuffer sTrk3,
                          StringBuffer sPAN,
                          Java.Util.Concurrent.Atomic.AtomicInteger aiPANSeq,
                          StringBuffer sAppLabel,
                          Java.Util.Concurrent.Atomic.AtomicInteger aiServCode,
                          StringBuffer sCardHolder,
                          StringBuffer sApplExpir,
                          Java.Util.Concurrent.Atomic.AtomicInteger bCardExtNum,
                          StringBuffer sBalance,
                          Java.Util.Concurrent.Atomic.AtomicLong alIssuerCode,
                          StringBuffer sAcquirerData)
                {
                    var a = JNIEnv.FindClass("br/com/gertec/pinpad/PPC");

                    if (id_ppc_GetEMVCard == IntPtr.Zero)
                    {
                        id_ppc_GetEMVCard = JNIEnv.GetMethodID(ppc.Handle, "PPC", "(BBBLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/concurrent/atomic/AtomicInteger;Ljava/util/concurrent/atomic/AtomicInteger;Ljava/util/concurrent/atomic/AtomicInteger;Ljava/util/concurrent/atomic/AtomicInteger;Ljava/util/concurrent/atomic/AtomicInteger;Ljava/lang/StringBuffer;Ljava/lang/StringBuffer;Ljava/lang/StringBuffer;Ljava/lang/StringBuffer;Ljava/util/concurrent/atomic/AtomicInteger;Ljava/lang/StringBuffer;Ljava/util/concurrent/atomic/AtomicInteger;Ljava/lang/StringBuffer;Ljava/lang/StringBuffer;Ljava/util/concurrent/atomic/AtomicInteger;Ljava/lang/StringBuffer;Ljava/util/concurrent/atomic/AtomicLong;Ljava/lang/StringBuffer;)V");
                    }


                    JNIEnv.CallVoidMethod(ppc.Handle, id_ppc_GetEMVCard, new JValue(bNetwork),
                        new JValue(bAppType), new JValue(sIniAmount), new JValue(sDate), new JValue(sHour),
                        new JValue(sTimeStamp), new JValue(aiCardType), new JValue(aiChipLastStatus),
                        new JValue(aiAppTypeSelected), new JValue(aiNetworkSelected), new JValue(aiAIDIdx),
                        new JValue(sTrk1), new JValue(sTrk2), new JValue(sTrk3), new JValue(sPAN),
                        new JValue(aiPANSeq), new JValue(sAppLabel), new JValue(aiServCode),
                        new JValue(sCardHolder), new JValue(sApplExpir), new JValue(bCardExtNum),
                        new JValue(sBalance), new JValue(alIssuerCode), new JValue(sAcquirerData));

                }
            }

So, now when I use my binding generated class, I do have the missing method there receiving exactly same parameters as it should.

I've used the javap utility to get the method signature of JNI which came with this and is used on JNIEnv.GetMethodID:

public void PPC_GetEMVCard(byte, byte, byte, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.util.concurrent.atomic.AtomicInteger, java.util.concurrent.atomic.AtomicInteger, java.util.concurrent.atomic.AtomicInteger, java.util.concurrent.atomic.AtomicInteger, java.util.concurrent.atomic.AtomicInteger, java.lang.StringBuffer, java.lang.StringBuffer, java.lang.StringBuffer, java.lang.StringBuffer, java.util.concurrent.atomic.AtomicInteger, java.lang.StringBuffer, java.util.concurrent.atomic.AtomicInteger, java.lang.StringBuffer, java.lang.StringBuffer, java.util.concurrent.atomic.AtomicInteger, java.lang.StringBuffer, java.util.concurrent.atomic.AtomicLong, java.lang.StringBuffer)   throws java.lang.NullPointerException, br.com.gertec.pinpad.PPCBusyException, br.com.gertec.pinpad.PPCCommunicationException, br.com.gertec.pinpad.PPCEMVException, br.com.gertec.pinpad.PPCGSerPortException, br.com.gertec.pinpad.PPCHandleException, br.com.gertec.pinpad.PPCIdentificationException, br.com.gertec.pinpad.PPCJNIException, br.com.gertec.pinpad.PPCProtocolCommandException, br.com.gertec.pinpad.PPCProtocolMessagesException, br.com.gertec.pinpad.PPCSerialPortException, br.com.gertec.pinpad.PPCGeneralException;
  Signature: (BBBLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/concurrent/atomic/AtomicInteger;Ljava/util/concurrent/atomic/AtomicInteger;Ljava/util/concurrent/atomic/AtomicInteger;Ljava/util/concurrent/atomic/AtomicInteger;Ljava/util/concurrent/atomic/AtomicInteger;Ljava/lang/StringBuffer;Ljava/lang/StringBuffer;Ljava/lang/StringBuffer;Ljava/lang/StringBuffer;Ljava/util/concurrent/atomic/AtomicInteger;Ljava/lang/StringBuffer;Ljava/util/concurrent/atomic/AtomicInteger;Ljava/lang/StringBuffer;Ljava/lang/StringBuffer;Ljava/util/concurrent/atomic/AtomicInteger;Ljava/lang/StringBuffer;Ljava/util/concurrent/atomic/AtomicLong;Ljava/lang/StringBuffer;)V

So far so good... I'm instantiating the binding generated class, calling all methods that it generates just fine... The only problem is when I'm calling the method I've created and it just crash the app and display this(really long) dump on output window:

    11-28 21:09:38.048 F/art     ( 3140): art/runtime/check_jni.cc:65] JNI DETECTED ERROR IN APPLICATION: jclass has wrong type: br.com.gertec.pinpad.PPC
    11-28 21:09:38.048 F/art     ( 3140): art/runtime/check_jni.cc:65]     in call to GetMethodID
    11-28 21:09:38.048 F/art     ( 3140): art/runtime/check_jni.cc:65]     from void mono.android.view.View_OnClickListenerImplementor.n_onClick(android.view.View)
    11-28 21:09:38.048 F/art     ( 3140): art/runtime/check_jni.cc:65] "main" prio=5 tid=1 Runnable
    11-28 21:09:38.048 F/art     ( 3140): art/runtime/check_jni.cc:65]   | group="main" sCount=0 dsCount=0 obj=0x73ada2e0 self=0xb874e530
    11-28 21:09:38.048 F/art     ( 3140): art/runtime/check_jni.cc:65]   | sysTid=3140 nice=0 cgrp=apps sched=0/0 handle=0xb6fb5ec8
    11-28 21:09:38.048 F/art     ( 3140): art/runtime/check_jni.cc:65]   | state=R schedstat=( 0 0 0 ) utm=260 stm=41 core=0 HZ=100
    11-28 21:09:38.048 F/art     ( 3140): art/runtime/check_jni.cc:65]   | stack=0xbe4c8000-0xbe4ca000 stackSize=8MB
    11-28 21:09:38.048 F/art     ( 3140): art/runtime/check_jni.cc:65]   | held mutexes= "mutator lock"(shared held)
    11-28 21:09:38.048 F/art     ( 3140): art/runtime/check_jni.cc:65]   native: #00 pc 00004c58  /system/lib/libbacktrace_libc++.so (UnwindCurrent::Unwind(unsigned int, ucontext*)+23)
    11-28 21:09:38.048 F/art     ( 3140): art/runtime/check_jni.cc:65]   native: #01 pc 000034c1  /system/lib/libbacktrace_libc++.so (Backtrace::Unwind(unsigned int, ucontext*)+8)
    11-28 21:09:38.048 F/art     ( 3140): art/runtime/check_jni.cc:65]   native: #02 pc 00252745  /system/lib/libart.so (art::DumpNativeStack(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, int, char const*, art::mirror::ArtMethod*)+84)
    11-28 21:09:38.048 F/art     ( 3140): art/runtime/check_jni.cc:65]   native: #03 pc 00236223  /system/lib/libart.so (art::Thread::Dump(std::__1::basic_ostream<char, std::__1::char_traits<char> >&) const+162)
    11-28 21:09:38.048 F/art     ( 3140): art/runtime/check_jni.cc:65]   native: #04 pc 000b1285  /system/lib/libart.so (art::JniAbort(char const*, char const*)+620)
    11-28 21:09:38.048 F/art     ( 3140): art/runtime/check_jni.cc:65]   native: #05 pc 000b19b5  /system/lib/libart.so (art::JniAbortF(char const*, char const*, ...)+68)
    11-28 21:09:38.048 F/art     ( 3140): art/runtime/check_jni.cc:65]   native: #06 pc 000b3385  /system/lib/libart.so (art::ScopedCheck::CheckInstance(art::ScopedCheck::InstanceKind, _jobject*)+172)
    11-28 21:09:38.048 F/art     ( 3140): art/runtime/check_jni.cc:65]   native: #07 pc 000b3dbb  /system/lib/libart.so (art::ScopedCheck::Check(bool, char const*, ...) (.constprop.128)+514)
    11-28 21:09:38.048 F/art     ( 3140): art/runtime/check_jni.cc:65]   native: #08 pc 000b7087  /system/lib/libart.so (art::CheckJNI::GetMethodID(_JNIEnv*, _jclass*, char const*, char const*)+58)
    11-28 21:09:38.048 F/art     ( 3140): art/runtime/check_jni.cc:65]   native: #09 pc 0005fa14   (???)
    11-28 21:09:38.049 F/art     ( 3140): art/runtime/check_jni.cc:65]   at mono.android.view.View_OnClickListenerImplementor.n_onClick(Native method)
    11-28 21:09:38.049 F/art     ( 3140): art/runtime/check_jni.cc:65]   at mono.android.view.View_OnClickListenerImplementor.onClick(View_OnClickListenerImplementor.java:29)
    11-28 21:09:38.049 F/art     ( 3140): art/runtime/check_jni.cc:65]   at android.view.View.performClick(View.java:4756)
    11-28 21:09:38.049 F/art     ( 3140): art/runtime/check_jni.cc:65]   at android.view.View$PerformClick.run(View.java:19749)
    11-28 21:09:38.049 F/art     ( 3140): art/runtime/check_jni.cc:65]   at android.os.Handler.handleCallback(Handler.java:739)
    11-28 21:09:38.049 F/art     ( 3140): art/runtime/check_jni.cc:65]   at android.os.Handler.dispatchMessage(Handler.java:95)
    11-28 21:09:38.049 F/art     ( 3140): art/runtime/check_jni.cc:65]   at android.os.Looper.loop(Looper.java:135)
    11-28 21:09:38.049 F/art     ( 3140): art/runtime/check_jni.cc:65]   at android.app.ActivityThread.main(ActivityThread.java:5221)
    11-28 21:09:38.049 F/art     ( 3140): art/runtime/check_jni.cc:65]   at java.lang.reflect.Method.invoke!(Native method)
    11-28 21:09:38.049 F/art     ( 3140): art/runtime/check_jni.cc:65]   at java.lang.reflect.Method.invoke(Method.java:372)
    11-28 21:09:38.049 F/art     ( 3140): art/runtime/check_jni.cc:65]   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
    11-28 21:09:38.049 F/art     ( 3140): art/runtime/check_jni.cc:65]   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
    11-28 21:09:38.049 F/art     ( 3140): art/runtime/check_jni.cc:65] 
    11-28 21:09:38.368 F/art     ( 3140): art/runtime/runtime.cc:284] Runtime aborting...
    11-28 21:09:38.368 F/art     ( 3140): art/runtime/runtime.cc:284] Aborting thread:
    11-28 21:09:38.368 F/art     ( 3140): art/runtime/runtime.cc:284] "main" prio=5 tid=1 Native
    11-28 21:09:38.368 F/art     ( 3140): art/runtime/runtime.cc:284]   | group="" sCount=0 dsCount=0 obj=0x73ada2e0 self=0xb874e530
    11-28 21:09:38.368 F/art     ( 3140): art/runtime/runtime.cc:284]   | sysTid=3140 nice=0 cgrp=apps sched=0/0 handle=0xb6fb5ec8
    11-28 21:09:38.368 F/art     ( 3140): art/runtime/runtime.cc:284]   | state=R schedstat=( 0 0 0 ) utm=264 stm=42 core=0 HZ=100
    11-28 21:09:38.369 F/art     ( 3140): art/runtime/runtime.cc:284]   | stack=0xbe4c8000-0xbe4ca000 stackSize=8MB
    11-28 21:09:38.369 F/art     ( 3140): art/runtime/runtime.cc:284]   | held mutexes= "abort lock" "mutator lock"(shared held)

What am I doing wrong?

PS: There is a lot more logs dumbing the abortion of all threads... For the sake of simplicity I've just posted the first block.

Thanks I really appreciate the help!
Gutemberg

Answers

  • CheesebaronCheesebaron DKInsider, University mod

    What you could do is to make a class which just hold all those values and passed in as a single argument into a method, which subsequently calls that method with all those arguments. Just strip the method out of the binding by removing the node.

  • That is what I'm trying to do
    look at **PPCBindingExtensions ** class. It is even in another assemlby... There is the problem...

  • Ok, I've moved one step forward... The documentation don't mention that the first parameter of GetMethodID is a CLASS pointer/handler, instead of a intance pointer/handler.

    So now I did:

    var classHandler = JNIEnv.FindClass("br/com/gertec/pinpad/PPC");

    And

    JNIEnv.GetMethodID(classHandler,....
    

    And I now have the the method pointer/handler.

    Now I have another crash saying that I'm passing invalid parameters to the CallVoidMethod(), that is sending to the native methods:

            11-28 22:17:18.322 E/art     ( 7365): JNI ERROR (app bug): attempt to pass an instance of java.lang.StringBuffer as argument 12 to void br.com.gertec.pinpad.PPC.PPC_GetEMVCard(byte, byte, byte, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.util.concurrent.atomic.AtomicInteger, java.util.concurrent.atomic.AtomicInteger, java.util.concurrent.atomic.AtomicInteger, java.util.concurrent.atomic.AtomicInteger, java.util.concurrent.atomic.AtomicInteger, java.lang.StringBuffer, java.lang.StringBuffer, java.lang.StringBuffer, java.lang.StringBuffer, java.util.concurrent.atomic.AtomicInteger, java.lang.StringBuffer, java.util.concurrent.atomic.AtomicInteger, java.lang.StringBuffer, java.lang.StringBuffer, java.util.concurrent.atomic.AtomicInteger, java.lang.StringBuffer, java.util.concurrent.atomic.AtomicLong, java.lang.StringBuffer)
            11-28 22:17:18.322 E/art     ( 7365): JNI ERROR (app bug): attempt to pass an instance of java.util.concurrent.atomic.AtomicInteger as argument 16 to void br.com.gertec.pinpad.PPC.PPC_GetEMVCard(byte, byte, byte, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.util.concurrent.atomic.AtomicInteger, java.util.concurrent.atomic.AtomicInteger, java.util.concurrent.atomic.AtomicInteger, java.util.concurrent.atomic.AtomicInteger, java.util.concurrent.atomic.AtomicInteger, java.lang.StringBuffer, java.lang.StringBuffer, java.lang.StringBuffer, java.lang.StringBuffer, java.util.concurrent.atomic.AtomicInteger, java.lang.StringBuffer, java.util.concurrent.atomic.AtomicInteger, java.lang.StringBuffer, java.lang.StringBuffer, java.util.concurrent.atomic.AtomicInteger, java.lang.StringBuffer, java.util.concurrent.atomic.AtomicLong, java.lang.StringBuffer)
    
        (and more others like this)
    

    The point is, this is, as you can see on the main post, there are all parameters being passed, and here is the Java signature of the method:

    public void PPC_GetEMVCard(byte, byte, byte, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.util.concurrent.atomic.AtomicInteger, java.util.concurrent.atomic.AtomicInteger, java.util.concurrent.atomic.AtomicInteger, java.util.concurrent.atomic.AtomicInteger, java.util.concurrent.atomic.AtomicInteger, java.lang.StringBuffer, java.lang.StringBuffer, java.lang.StringBuffer, java.lang.StringBuffer, java.util.concurrent.atomic.AtomicInteger, java.lang.StringBuffer, java.util.concurrent.atomic.AtomicInteger, java.lang.StringBuffer, java.lang.StringBuffer, java.util.concurrent.atomic.AtomicInteger, java.lang.StringBuffer, java.util.concurrent.atomic.AtomicLong, java.lang.StringBuffer) throws java.lang.NullPointerException, br.com.gertec.pinpad.PPCBusyException, br.com.gertec.pinpad.PPCCommunicationException, br.com.gertec.pinpad.PPCEMVException, br.com.gertec.pinpad.PPCGSerPortException, br.com.gertec.pinpad.PPCHandleException, br.com.gertec.pinpad.PPCIdentificationException, br.com.gertec.pinpad.PPCJNIException, br.com.gertec.pinpad.PPCProtocolCommandException, br.com.gertec.pinpad.PPCProtocolMessagesException, br.com.gertec.pinpad.PPCSerialPortException, br.com.gertec.pinpad.PPCGeneralException;

    I can't see any discrepancy...

Sign In or Register to comment.