user1505986
user1505986

Reputation: 267

How to call a Java function via JNI from a signal handler function in Android

My objective is to send a signal from kernel to a Android service running in the userspace.On receiving this signal, the service should make an IOCTL call back to the kernel. After it gets data from the kernel through this ioctl call,it has to display to the user. For this, i call a native method from my Java Service, which registers the sigaction structure, which includes the handler function for this signal. This handler function will make the IOCTL call and call a Java Function to pass the string to the Java service.

Here is the signal.java class

public class signal {
static{
    System.loadLibrary("signal");
}
public native String hello();

public String messageMe(String s)
{
    if(null != MainActivity.mUiHandler)
    {
        Message msgToActivity = new Message();
        msgToActivity.what = 0;

            msgToActivity.obj  = s; // you can put extra message here

        MainActivity.mUiHandler.sendMessage(msgToActivity);
    }

    System.out.println(s);
        return s;
}

}

I need to call this "messageMe" function from the signal handler. Here is the native hello() function which registers the sigaction structure.

JNIEXPORT jstring JNICALL Java_com_example_service_signal_hello
(JNIEnv * env, jobject obj) {

 int configfd;
char buf[10];
/* setup the signal handler for SIG_TEST
 * SA_SIGINFO -> we want the signal handler function with 3 arguments
 */
struct sigaction sig;
sig.sa_sigaction = receiveData;
sig.sa_flags = SA_SIGINFO;
sigaction(SIG_TEST, &sig,NULL);
}

The receiveData is the handler function. Here it goes.

void receiveData(int n, siginfo_t *info,void* unused) {
    char buf[200];
    char *msg = "hello world";
    int fd = -1;
    if ((fd = open("/dev/my_device", O_RDWR)) < 0) {
            perror("on");
            return;
    }
    if(ioctl(fd, READ_IOCTL, buf) < 0)
            perror("second ioctl");

     jstring jstr = (*env)->NewStringUTF(env, buf);
     jclass *clazz = (*env)->GetObjectClass(env, obj);
     jmethodID messageMe = (*env)->GetMethodID(env,clazz, "messageMe", "(Ljava/lang/String;)Ljava/lang/String;");
     jobject result = (*env)->CallObjectMethod(env,obj, messageMe, jstr);

    printf("message: %s\n", buf);

} This handler function should call the Java function "messageMe" and pass the string it read from the kernel as an argument. But it does not have Environment variables JNIEnv * and jobject obj. When I maintained a global pointers to these variables in the hello() function, and used them here, it was giving NoClassDefFoundError. How do I now send the string from this signal handler to the Java function?

Upvotes: 2

Views: 3541

Answers (2)

user1505986
user1505986

Reputation: 267

I have the following global variables. I cached these objects for future use.

JavaVM* vm;
static jclass cl;
static jobject ob;

In the hello function, i made global references for the above variables.

JNIEXPORT jstring JNICALL Java_com_example_service_signal_hello
(JNIEnv * env, jobject obj) {
(*env)->GetJavaVM(env,&vm);
ob = (*env)->NewGlobalRef(env,obj);
jclass clazz = (*env)->FindClass(env,"com/example/service/signal");
cl = (*env)->NewGlobalRef(env,clazz);
}

Now I used these in the handler function

void receiveData(int n, siginfo_t *info,void* unused) {
//other code
JNIEnv* env = NULL;
    if(vm==NULL)
        return;
    (*vm)->AttachCurrentThread(vm,&env,0);
 jmethodID messageMe = (*env)->GetStaticMethodID(env,cl, "messageMe", "(Ljava/lang/String;)Ljava/lang/String;");
jobject result = (*env)->CallStaticObjectMethod(env,cl, messageMe, jstr);
}

One change I made was the use of static method instead of a normal one. So i didn't have to use a specific instance of the class. If the method is not static, the global variable "ob" can be used in the CallObjectMethod.

Upvotes: 1

mbrenon
mbrenon

Reputation: 4941

As far as i know, the GetObjectClass method returns a jclass, not a jclass *.

In your receiveData function, you should replace

jclass *clazz = (*env)->GetObjectClass(env, obj);

by

jclass clazz = (*env)->GetObjectClass(env, obj);

Upvotes: 0

Related Questions