Android JNI and interfaces and creating classes

1,500 views
Skip to first unread message

Felipe Monteiro de Carvalho

unread,
Jun 20, 2012, 1:29:30 AM6/20/12
to andro...@googlegroups.com
Hello,

When writing JNI code a lot of time I have trouble because many methods require me to pass a object which implements an interface, for example:

public interface SYNCPROC { 
void SYNCPROC(int handle, int channel, int data, Object user);
}
public static native int BASS_ChannelSetSync(int handle, int type, long param, SYNCPROC proc, Object user);

Is it possible to call this function correctly from JNI? How would I create a new class which implements the interface SYNCPROC in JNI?

thanks,

Felipe Monteiro de Carvalho

David Turner

unread,
Jun 20, 2012, 6:35:48 AM6/20/12
to andro...@googlegroups.com
Creating a new class at runtime from JNI is probably too much work for your needs (you essentially need to generate Dalvik bytecode on the fly, then load it with a DexClassLoader(), not for the faint of heart).

You'd probably better writing a little Java instead, i.e. a class that implements the interface through a method that calls a custom native method you could hook up to whatever you want from the native side.
 
thanks,

Felipe Monteiro de Carvalho

--
You received this message because you are subscribed to the Google Groups "android-ndk" group.
To view this discussion on the web visit https://groups.google.com/d/msg/android-ndk/-/pr00SKylmywJ.
To post to this group, send email to andro...@googlegroups.com.
To unsubscribe from this group, send email to android-ndk...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/android-ndk?hl=en.

Felipe Monteiro de Carvalho

unread,
Jun 20, 2012, 4:33:37 PM6/20/12
to andro...@googlegroups.com
On Wednesday, June 20, 2012 12:35:48 PM UTC+2, Digit wrote:
Creating a new class at runtime from JNI is probably too much work for your needs (you essentially need to generate Dalvik bytecode on the fly, then load it with a DexClassLoader(), not for the faint of heart).

You'd probably better writing a little Java instead, i.e. a class that implements the interface through a method that calls a custom native method you could hook up to whatever you want from the native side. 
 
Quite the contrary, I am very much interrested in any information, if you have any links, documentation or tutorial on that it would be great.

I am familiar with Java assembler and JNI, so it's not scary for me. And in my case being able to do things 100% in the native side would be really excellent.

F.Stein

unread,
Jun 20, 2012, 11:30:49 PM6/20/12
to andro...@googlegroups.com
Felipe,

Do you needed a unique code for each SYNCPROC object? Or you have some limit of SYNCPROC method realizations?
Also. Is there need to use native code in SYNCPROC method?

четверг, 21 июня 2012 г., 3:33:37 UTC+7 пользователь Felipe Monteiro de Carvalho написал:

Felipe Monteiro de Carvalho

unread,
Jun 21, 2012, 4:21:18 AM6/21/12
to andro...@googlegroups.com
On Thursday, June 21, 2012 5:30:49 AM UTC+2, F.Stein wrote:
Do you needed a unique code for each SYNCPROC object? 

No, they could all do the same thing: Call a native routine passing the received arguments. Only 1 operation in the method.
 
Or you have some limit of SYNCPROC method realizations?
Also. Is there need to use native code in SYNCPROC method?

The SYNCPROC event handler should return the information back to the native code so it can handle there. I could have 1 single native routine like this which can handle all callbacks with a parameter AEventID to know from which routine the data is coming from:

public native void GeneralCallbackHandler(int AEventID, int param_int_1, int param_int_2, int param_int_3, Object param_obj_1, Object param_obj_2, double param_fp_1, double param_fp_2);

That should fit almost any kind of event handler. My class would then be:

public class MySYNCPROC implements SYNCPROC

  @Override void SYNCPROC(int handle, int channel, int data, Object user)
  {
    GeneralCallbackhandler(20, handle, channel, data, user, nil, 0, 0)
  };
}

Just need to figure out how to write that in bytecode now =)

Felipe Monteiro de Carvalho

David Turner

unread,
Jun 21, 2012, 5:52:03 AM6/21/12
to andro...@googlegroups.com
On Wed, Jun 20, 2012 at 10:33 PM, Felipe Monteiro de Carvalho <felipemonte...@gmail.com> wrote:
On Wednesday, June 20, 2012 12:35:48 PM UTC+2, Digit wrote:
Creating a new class at runtime from JNI is probably too much work for your needs (you essentially need to generate Dalvik bytecode on the fly, then load it with a DexClassLoader(), not for the faint of heart).

You'd probably better writing a little Java instead, i.e. a class that implements the interface through a method that calls a custom native method you could hook up to whatever you want from the native side. 
 
Quite the contrary, I am very much interrested in any information, if you have any links, documentation or tutorial on that it would be great.

Well, the usual way to do that in Java is to use a library to generate a .class file directly in memory, then load it with a JavaClassLoader()
The file contains a definition for a new class with one or more native methods that implements your interface.

In the Dalvik world, this won't work. You need to create a .dex file instead, which uses a completely different bytecode (and program representation).

If you program in Java, you could use a library like DexMaker to do just that. However, I suspect that you're doing this for your Pascal compiler. In this case, you'll likely need to reimplement this in a different language, i.e. either C or Pascal I guess.

Given that your needs are pretty light, writing this by hand might turn out to be simpler than having to use/port a full-blown Dex generation library to your environment.

Hope this helps

 
I am familiar with Java assembler and JNI, so it's not scary for me. And in my case being able to do things 100% in the native side would be really excellent.

thanks,

Felipe Monteiro de Carvalho

--
You received this message because you are subscribed to the Google Groups "android-ndk" group.
To view this discussion on the web visit https://groups.google.com/d/msg/android-ndk/-/7BkZsEp7pSgJ.

F.Stein

unread,
Jun 21, 2012, 6:30:28 AM6/21/12
to andro...@googlegroups.com
Hmm... Felipe, i can't understand, why you can't delegate the SYNCPROC objects creation to java side?
Maybe i don't see some crucial moments?
Even if you have no java code in your project, you may create one factory-class for this purposes.
Something like this...

//java
public class cSyncProcFactory {

  private class cSyncNativeStub implements SYNCPROC {

    private int m_proc_handle = 0;

    public cSyncNativeObject( int proc_handle ){
      m_proc_handle = proc_hanble;
    };

    @override
    public void SYNCPROC(int handle, int channel, int data, Object user){
      call_handle( m_proc_handle, handle, channel, data user );
    };

    private native void call_handle( int proc_handle, int handle, int channel, int data, Object user );
  }

  public static SYNCPROC make_object( int proc_handle ){
    return new cSyncNativeObject( proc_handle );
  };
};

If you need to create a  SYNCPROC object, just call cSyncProcFactory.make_object() via JNI. Inside native "call_handle" you may do what ever you want with proc_handle, it may be a object ID or a hard pointer to native function.
this is a question of your desire. :)

четверг, 21 июня 2012 г., 15:21:18 UTC+7 пользователь Felipe Monteiro de Carvalho написал:

Felipe Monteiro de Carvalho

unread,
Jun 21, 2012, 8:02:05 AM6/21/12
to andro...@googlegroups.com
On Thursday, June 21, 2012 12:30:28 PM UTC+2, F.Stein wrote:
Hmm... Felipe, i can't understand, why you can't delegate the SYNCPROC objects creation to java side?
Maybe i don't see some crucial moments?

I am not writting any particular application, I am writing a framework for Pascal developers to write Pascal applications for Android.

In this sense it is vastly superior if the java part of the application can be as small as possible and Pascal developers should not need to modify it at all, or know Java at all to use my framework.

But then they want to call Java APIs, and JNI is not up to the task as it does not support creating classes, so I need to expand here to cover this area and allow Pascal developers to access the Java APIs without Java.
 
Even if you have no java code in your project, you may create one factory-class for this purposes.
Something like this...

I can't because I don't know which classes the developer will want to access. Bass is just 1 API that 1 particular developer wants to access. Each Pascal developer using my framework will likely use different classes, so we would need hundreds of factory classes and it would increase massively the amount of dependencies ... etc

Felipe Monteiro de Carvalho

Chris Stratton

unread,
Jun 21, 2012, 11:09:57 AM6/21/12
to android-ndk
On Jun 21, 8:02 am, Felipe Monteiro de Carvalho
<felipemonteiro.carva...@gmail.com> wrote:
> I am not writting any particular application, I am writing a framework for
> Pascal developers to write Pascal applications for Android.
>
> But then they want to call Java APIs, and JNI is not up to the task as it
> does not support creating classes, so I need to expand here to cover this
> area and allow Pascal developers to access the Java APIs without Java.

You presumably run into the same problems behind why only a limited
set of the java APIs have corresponding native-activity C APIs.

The easy answer would be to restrict your users to those C APIs,
though that may not be an acceptable answer.

Felipe Monteiro de Carvalho

unread,
Jun 21, 2012, 11:54:38 AM6/21/12
to andro...@googlegroups.com
On Thursday, June 21, 2012 5:09:57 PM UTC+2, Chris Stratton wrote:
You presumably run into the same problems behind why only a limited 
set of the java APIs have corresponding native-activity C APIs.

The easy answer would be to restrict your users to those C APIs,
though that may not be an acceptable answer.

Yes, the major problem that I have with Android development is that the number of libraries exposed by the NDK is claustrophobically small. It is the minimal, really bare-minimal possible for us to survive. Not even freetype is available so we have invested into resurrecting the original freetype sources written in Pascal and we made it =) http://wiki.lazarus.freepascal.org/LazFreeType

But there is only so much our community can do, so we need access to the Java APIs for a lot of other functionality which is not covered in our Lazarus libraries.

Felipe Monteiro de Carvalho

F.Stein

unread,
Jun 22, 2012, 2:35:00 AM6/22/12
to andro...@googlegroups.com
I am not writting any particular application, I am writing a framework for Pascal developers to write Pascal applications for Android.

That is crucial. I see now. :)
Maybe in this case it will be better to investigate the DexGen project? ( https://github.com/android/platform_dalvik/tree/master/dexgen )

a1

unread,
Jun 22, 2012, 3:57:21 AM6/22/12
to andro...@googlegroups.com

You'd probably better writing a little Java instead, i.e. a class that implements the interface through a method that calls a custom native method you could hook up to whatever you want from the native side. 
 
Quite the contrary, I am very much interrested in any information, if you have any links, documentation or tutorial on that it would be great.

Well, the usual way to do that in Java is to use a library to generate a .class file directly in memory, then load it with a JavaClassLoader()
The file contains a definition for a new class with one or more native methods that implements your interface.

That was a usual way priori to 1.4 which introduced dynamic proxies (java.lang.reflect.Proxy) which are supported on android as well (at least documentation states so, never tried it). Dynamic proxy is exactly what OP needs - dynamic class generator. Since it delegates invocation to standardized InvocationHandler interface, it's possible to create mediation layer between native and VM side.

First one will need a InvocationHandler implementation that delegates all calls to native side:

public class NativeInvocationHandler implements InvocationHandler {
public NativeInvocationHandler(long ptr) {
this.ptr = ptr;
}
Object invoke(Object proxy, Method method, Object[] args) {
return invoke0(proxy, method, args);
}
native private Object invoke0(Object proxy, Method method, Object[] args);
private long ptr;
}

where pointer should be pointer to native representation of InvocationHandler something like:

class NativeInvocationHandler {
public:
virtual ~NativeInvocationHandler();
virtual jobject Invoke(JNIEnv *, jobject method, jobjectArray args) = 0;
};

and a piece of glue code:

jobject invoke0(JNIEnv *env, jobject thiz, jobject method, jobjectArray args) {
jfieldID ptrField = env->GetFieldID(env->GetObjectClass(thiz), "ptr", "J");
jlong jptr = env->GetLongField(thiz, ptrField);
NativeInvocationHandler *h = reinterpret_cast<NativeInvocationHandler> (jptr);
return h->Invoke(env, method, args);
}

Now, there is a need for a small piece of java code but it's static so as I understand this is fine with OP.

Disclaimer: I did use this technique on embedded systems with java CDC VM, but never tried it on android so I have no idea if everything will work as advertised.

--
Bart

Felipe Monteiro de Carvalho

unread,
Jun 24, 2012, 5:36:35 AM6/24/12
to andro...@googlegroups.com
On Friday, June 22, 2012 9:57:21 AM UTC+2, a1 wrote:
That was a usual way priori to 1.4 which introduced dynamic proxies (java.lang.reflect.Proxy) which are supported on android as well (at least documentation states so, never tried it). Dynamic proxy is exactly what OP needs - dynamic class generator. Since it delegates invocation to standardized InvocationHandler interface, it's possible to create mediation layer between native and VM side.

Thanks a lot! This is indeed the best way to go. For me it is no problem to have some Java code if it is static. I will be working on implementing the solution this way =) Surely it is much better then writing raw bytecode.

thanks again,

Felipe Monteiro de Carvalho
Reply all
Reply to author
Forward
0 new messages