Reputation: 39
I am new with c and i am trying to create this project in android studio that reads linux input with /dev/input/event* directory, the other part that read's so is an executable program (run with root access), that writes a fifo pipe (named) that can be read with this program and send input_event struct back to java.
C code:
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 code:
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();
}
}
The problem is, while this program is executing it works fine but when i try to exit the loop it crashes before it returns to java code
A/libc: Fatal signal 11 (SIGSEGV), code 2 (SEGV_ACCERR), fault addr 0x74e8995000 in tid 14435 (Thread-7), pid 13933 (e_app.bixby_map)
that's the error i get. any help?
Upvotes: 0
Views: 202
Reputation: 39
I had like to thank you both @Michael and @Alex Cohn for their helpful comment.
After what @Michael said, i re-read the JNI Documentation from oracle and JavaVM and JNIEnv and Threads i noticed my mistake that i didn't read them carefully before, after so I used AttachCurrentThread
to achieve what i want as described, but then again after what @Alex Cohn said, i decided to make the threading made inside the java code, it's much easier to handle and debug, and here is the final code:
C code:
static boolean READ_EVENT_TASK_LOOP = false;
static char * path = NULL;
static struct pollfd fds[1];
void *Java_com_yacine_1app_bixby_1map_event_CustomEvent_releaseListener(__unused JNIEnv *env, __unused jobject obj){
READ_EVENT_TASK_LOOP = false;
char *full_path = (char*) malloc(500 * sizeof(char));
sprintf(full_path, "%s/%s", path, INPUT_CUSTOM_EVENT_FIFIO_FILE);
remove(full_path);
close(fds[0].fd);
path = NULL;
//free(fds);
//_exit(0);
return NULL;
}
void *Java_com_yacine_1app_bixby_1map_event_CustomEvent_listenTo(JNIEnv *env, jobject obj) {
if(!READ_EVENT_TASK_LOOP) return NULL;
struct input_event in;
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);
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");
fds[0].fd = open(full_path, O_RDONLY);
if(fds[0].fd < 0){
printf("Error with reading %s\n", full_path);
return NULL;
}
fds[0].events = POLLIN;
//pthread_cleanup_push(cleanup, end_hash_fd)
while (READ_EVENT_TASK_LOOP) {
poll(fds, 1, 500);
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);
}
}
//close(fds[0].fd);
return NULL;
}
void *Java_com_yacine_1app_bixby_1map_event_CustomEvent_initialize(JNIEnv *env, __unused jobject obj, jstring shared_path) {
READ_EVENT_TASK_LOOP = true;
path = (char*) (*env)->GetStringUTFChars(env, shared_path, NULL);
return NULL;
}
Java code:
public class CustomEvent {
public static CustomEvent newInstance(){ return new CustomEvent(); }
private boolean initialized = false;
private String path;
private OnEventListener onEventListener;
private OnReleasedListener onReleasedListener;
private OnStartedListener onStartedListener;
private RootManager rm;
private Thread startThread, stopThread;
private final Runnable start = ()->{
try {
this.rm.exec("./PsB -d 6 -o " + this.path);
} catch (IOException e) {
e.printStackTrace();
}
if(this.onStartedListener != null) this.onStartedListener.onStarted();
this.listenTo();
}, stop = ()->{
this.releaseListener();
this.startThread = null;
this.stopThread = null;
try {
this.rm.exit();
this.rm = null;
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
this.initialized = false;
if(this.onReleasedListener != null) this.onReleasedListener.onReleased();
};
static {
System.loadLibrary("LinuxEventReader");
}
private CustomEvent(){ }
public void init(String path){
this.path = path;
this.initialize(this.path);
this.rm = new RootManager();
if(this.rm.isRootAccess())return;
try {
this.rm.setDir(this.path + "/files/exec");
this.rm.requestRoot();
this.rm.exec("chmod +x PsB");
this.startThread = new Thread(this.start);
this.stopThread = new Thread(this.stop);
this.initialized = true;
} catch (IOException e) {
e.printStackTrace();
}
}
public void startListening(){
if(!this.initialized) throw new IllegalStateException();
this.startThread.start();
}
public void release(){
if(!this.initialized) throw new IllegalStateException();
this.stopThread.start();
}
public void setOnEventListener(OnEventListener onEventListener) { this.onEventListener = onEventListener; }
public void setOnReleasedListener(OnReleasedListener onReleasedListener) { this.onReleasedListener = onReleasedListener; }
public void setOnStartedListener(OnStartedListener onStartedListener) { this.onStartedListener = onStartedListener; }
@SuppressWarnings("unused")
private synchronized void onEvent(InputEventStruct inputEvent){
if(this.onEventListener != null) this.onEventListener.onEvent(inputEvent);
}
@SuppressWarnings("unused")
private void onError(String err){
Log.e("ERROR", err);
}
private native void listenTo();
private native void releaseListener();
private native void initialize(String path);
}
If anything i made is wrong or not accurate i will appreciate more help :)
Upvotes: 0