如何通过JNI从Android中的信号处理函数调用Java函数

如何通过JNI从Android中的信号处理函数调用Java函数,java,android,android-ndk,java-native-interface,Java,Android,Android Ndk,Java Native Interface,我的目标是从内核向运行在用户空间中的Android服务发送一个信号。一旦收到这个信号,服务应该向内核发出一个IOCTL回调。在通过这个ioctl调用从内核获取数据之后,它必须向用户显示。为此,我从Java服务调用一个本机方法,该方法注册sigaction结构,其中包括该信号的处理函数。这个处理函数将进行IOCTL调用,并调用一个Java函数将字符串传递给Java服务 下面是signal.java类 public class signal { static{ System.loadLibr

我的目标是从内核向运行在用户空间中的Android服务发送一个信号。一旦收到这个信号,服务应该向内核发出一个IOCTL回调。在通过这个ioctl调用从内核获取数据之后,它必须向用户显示。为此,我从Java服务调用一个本机方法,该方法注册sigaction结构,其中包括该信号的处理函数。这个处理函数将进行IOCTL调用,并调用一个Java函数将字符串传递给Java服务

下面是signal.java类

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;
}
}

我需要从信号处理程序调用这个“messageMe”函数。 下面是注册sigaction结构的本机hello()函数

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);
}
receiveData是处理程序函数。来了

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);
void receiveData(int n,siginfo\u t*info,void*unused){
char-buf[200];
char*msg=“你好,世界”;
int-fd=-1;
如果((fd=open(“/dev/my_device”,O_RDWR))<0){
佩罗尔(“安”);
返回;
}
if(ioctl(fd,READ_ioctl,buf)<0)
perror(“第二ioctl”);
jstringjstr=(*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(“消息:%s\n”,buf);
} 这个处理函数应该调用Java函数“messageMe”,并将从内核读取的字符串作为参数传递给它。但它没有环境变量JNIEnv*和jobject obj。当我在hello()函数中维护指向这些变量的全局指针并在这里使用它们时,它给出了NoClassDefFoundError。
现在如何将字符串从这个信号处理程序发送到Java函数?

据我所知,
GetObjectClass
方法返回一个
jclass
,而不是
jclass*

receiveData
功能中,您应该替换

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


我有以下全局变量。我缓存了这些对象以备将来使用

JavaVM* vm;
static jclass cl;
static jobject ob;
在hello函数中,我对上述变量进行了全局引用

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);
}
现在我在处理函数中使用了这些

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);
}

我做的一个改变是使用静态方法而不是普通方法。因此,我不必使用该类的特定实例。如果该方法不是静态的,则全局变量“ob”可以在CallObjectMethod中使用。

虽然您的问题与此不同,但在我尝试缓存JavaVM指针并在处理程序中获得JNIEnv变量的顶部答案中引用了一个示例实现。但是getMethodID函数给出了一个挂起的异常NoClassDefFoundError,VM正在中止。在原始本机函数中执行此操作时,不会引发异常。为什么?是的,我后来意识到了。但这并没有解决问题。我终于解决了这个问题。我将发布一个答案。通常,在信号处理程序中尽可能少地执行操作是一个好主意,因为当信号到达时,您不知道当前线程处于什么状态。Dalvik VM通过使用
sigprocmask
阻止某些信号,并在
sigwait
中有一个专用的信号捕获线程,来处理它想要捕获的信号。(请参阅中的Init.cpp和SignalCatcher.cpp)如果可以使用该信号将特定线程作为目标,则不需要在所有其他线程上阻止它。
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);
}