【发布时间】:2021-08-29 04:04:06
【问题描述】:
我是 c 新手,我正在尝试在 android studio 中创建这个项目,该项目使用 /dev/input/event* 目录读取 linux 输入,读取的另一部分是可执行程序(以 root 访问权限运行),写入一个可以用这个程序读取的fifo管道(命名)并将input_event结构发送回java。
C 代码:
boolean READ_EVENT_TASK_LOOP = false;
pthread_t eventThread, eventTest;
void Java_com_yacine_1app_bixby_1map_event_CustomEvent_releaseListener(JNIEnv *env, jobject obj){
READ_EVENT_TASK_LOOP = false;
jclass ceClass = (*env)->GetObjectClass(env, obj);
jmethodID onEventId = (*env)->GetMethodID(env, ceClass, "onError", "(Ljava/lang/String;)V");
char msg[] = "No error were found!";
(*env)->CallVoidMethod(env, obj, onEventId, (*env)->NewStringUTF(env, msg));
}
void * eventCheckingThread(JNIEnv *env, jobject obj, jstring shared_path);
void Java_com_yacine_1app_bixby_1map_event_CustomEvent_listenTo(JNIEnv *env, jobject obj, jstring shared_path) {
int stat = pthread_create(&eventThread, NULL, eventCheckingThread(env, obj, shared_path), "Event Thread");
if(stat) return;
pthread_join(eventThread, NULL);
}
void *eventCheckingThread(JNIEnv *env, jobject obj, jstring shared_path){
READ_EVENT_TASK_LOOP = true;
jclass ceClass = (*env)->GetObjectClass(env, obj);
jmethodID onEventId = (*env)->GetMethodID(env, ceClass, "onEvent", "(Lcom/yacine_app/bixby_map/event/InputEventStruct;)V");
jclass inputEventClass = (*env)->FindClass(env, "com/yacine_app/bixby_map/event/InputEventStruct");
jobject inputEventObject = (*env)->GetObjectClass(env, inputEventClass);
jmethodID inputEventConstructor = (*env)->GetMethodID(env, inputEventObject, "<init>", "()V");
jobject inputEventInstance = (*env)->NewObject(env, inputEventClass, inputEventConstructor);
jfieldID inputEventInstanceTimeval = (*env)->GetFieldID(env, inputEventClass, "timeval", "Lcom/yacine_app/bixby_map/event/Timeval;");
jfieldID inputEventInstanceType = (*env)->GetFieldID(env, inputEventClass, "type", "S");
jfieldID inputEventInstanceCode = (*env)->GetFieldID(env, inputEventClass, "code", "S");
jfieldID inputEventInstanceValue = (*env)->GetFieldID(env, inputEventClass, "value", "I");
jclass timevalClass = (*env)->FindClass(env, "com/yacine_app/bixby_map/event/Timeval");
jobject timevalObject = (*env)->GetObjectClass(env, timevalClass);
jmethodID timevalInstanceId = (*env)->GetMethodID(env, timevalObject, "<init>", "()V");
jobject timevalInstance = (*env)->NewObject(env, timevalClass, timevalInstanceId);
jfieldID timevalInstanceTv_sec = (*env)->GetFieldID(env, timevalClass, "tv_sec", "I");
jfieldID timevalInstanceTv_usec = (*env)->GetFieldID(env, timevalClass, "tv_usec", "I");
const char *path = (*env)->GetStringUTFChars(env, shared_path, null);
struct input_event in;
struct pollfd fds[1];
char *full_exist_hash = (char*) malloc(500 * sizeof(char));
sprintf(full_exist_hash, "%s/%s", path, INPUT_CUSTOM_EVENT_END_HASH);
mkfifo(full_exist_hash, O_CREAT | S_IWUSR | S_IRUSR | S_IRGRP | S_IWOTH | S_IROTH | S_IWOTH);
int end_hash_fd = open(full_exist_hash, O_NONBLOCK | O_WRONLY);
if(end_hash_fd < 0){
printf("Error with reading %s\n", full_exist_hash);
_exit(-1);
}
char *full_path = (char*) malloc(500 * sizeof(char));
sprintf(full_path, "%s/%s", path, INPUT_CUSTOM_EVENT_FIFIO_FILE);
mkfifo(full_path, O_CREAT | S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH);
fds[0].fd = open(full_path, O_RDONLY);
if(fds[0].fd < 0){
printf("Error with reading %s\n", full_path);
_exit(-1);
}
fds[0].events = POLLIN;
while (READ_EVENT_TASK_LOOP) {
poll(fds, 1, 5000);
if(fds[0].revents){
read(fds[0].fd, &in, sizeof(in));
if(in.code | in.type | in.value > 0) {
(*env)->SetIntField(env, timevalInstance, timevalInstanceTv_sec, in.time.tv_sec);
(*env)->SetIntField(env, timevalInstance, timevalInstanceTv_usec, in.time.tv_usec);
(*env)->SetObjectField(env, inputEventInstance, inputEventInstanceTimeval, timevalInstance);
(*env)->SetShortField(env, inputEventInstance, inputEventInstanceType, in.type);
(*env)->SetShortField(env, inputEventInstance, inputEventInstanceCode, in.code);
(*env)->SetIntField(env, inputEventInstance, inputEventInstanceValue, in.value);
(*env)->CallVoidMethod(env, obj, onEventId, inputEventInstance);
}
//printf("time: %li, code: %hi, type: %hi, value: %d\n\r", in.time.tv_sec, in.code, in.type, in.value);
}
}
write(end_hash_fd, INPUT_CUSTOM_EVENT_END_HASH, strlen(INPUT_CUSTOM_EVENT_END_HASH));
close(end_hash_fd);
close(fds[0].fd);
}
Java 代码:
import android.util.Log;
public class CustomEvent {
public static CustomEvent newInstance(){
return new CustomEvent();
}
private String path;
private OnEventListener onEventListener;
private OnReleasedListener onReleasedListener;
private OnStartedListener onStartedListener;
public void setPath(String path) {
this.path = path;
}
public void setOnEventListener(OnEventListener onEventListener) { this.onEventListener = onEventListener; }
public void setOnReleasedListener(OnReleasedListener onReleasedListener) { this.onReleasedListener = onReleasedListener; }
public void setOnStartedListener(OnStartedListener onStartedListener) { this.onStartedListener = onStartedListener; }
private CustomEvent(){ }
static {
System.loadLibrary("LinuxEventReader");
}
private void onEvent(InputEventStruct inputEvent){
if(this.onEventListener != null) this.onEventListener.onEvent(inputEvent);
}
private void onError(String err){
Log.e("ERROR", err);
}
private native void listenTo(String path);
private native void releaseListener();
public void startListening(){
new Thread(()->{
if(this.onStartedListener != null) this.onStartedListener.onStarted();
listenTo(path);
}).start();
}
public void release(){
new Thread(()->{
releaseListener();
if(this.onReleasedListener != null) this.onReleasedListener.onReleased();
}).start();
}
}
问题是,当这个程序正在执行时,它工作正常,但是当我尝试退出循环时,它在返回到 java 代码之前崩溃了
A/libc: Fatal signal 11 (SIGSEGV), code 2 (SEGV_ACCERR), fault addr 0x74e8995000 in tid 14435 (Thread-7), pid 13933 (e_app.bixby_map)
这就是我得到的错误。有什么帮助吗?
【问题讨论】:
-
有两件事情很奇怪:1) 看起来您正在跨不同线程共享
JNIEnv*,这是您不应该做的。 2) 在eventCheckingThread的末尾没有return语句,即使它应该返回void *。 -
我相信@Michael 给出了正确的理由;
eventThread不能使用由不同 (Java) 线程传递的env。您可以轻松避免这种混乱:只需从Java_com_yacine_1app_bixby_1map_event_CustomEvent_listenTo()(本机 Java 方法)调用(同步)eventCheckingThread()函数。 -
用
AttachCurrentThread让它工作需要更多时间,但在java代码中创建线程更准确
标签: c android-studio cmake android-ndk java-native-interface