Я вызываю Java-метод из уровня JNI периодически (каждые 50 мс), используя timer_create. Мой метод Java (callback()) вызывается в течение некоторого времени, но после этого его вызов не будет вызван, и мое приложение зависает. Если я прикасаюсь к чему-либо на экране, я получаю ANR.JNI: Вызов метода Java из C периодически не работает
Чтобы проверить, не является ли проблема с таймером или вызовом JNI (вызов метода java), я прокомментировал все внутри обработчика(), за исключением оператора журнала. Я заметил, что журнал печатается непрерывно, что заставило меня прийти к выводу, что проблема заключается в вызове java-метода из обработчика().
Я не уверен, какой поток (UI или не-UI) этот вызов JNI выполняется, когда я использую AttachCurrentThread(). Если это сделано в потоке пользовательского интерфейса, то, пожалуйста, дайте мне знать, как заставить его работать на потоке, отличном от UI. Или есть другие проблемы в моем коде, которые вызывают это.
Если вы наблюдаете выходные данные, методы native и java вызываются непрерывно, но через некоторое время вызывается только собственный метод и после нескольких вызовов, которые тоже останавливаются.
/******************Native Code**************************/
void handler(int sig, siginfo_t *si, void *uc) {
JNIEnv * g_env;
__android_log_print(ANDROID_LOG_INFO, TAG, "Native handler");
int getEnvStat = (*g_vm)->GetEnv(g_vm,(void **)&g_env, JNI_VERSION_1_6);
if (getEnvStat == JNI_EDETACHED) {
if ((*g_vm)->AttachCurrentThread(g_vm, (void **) &g_env, NULL) != 0) {
}
} else if (getEnvStat == JNI_OK) {
} else if (getEnvStat == JNI_EVERSION) {
}
(*g_env)->CallVoidMethod(g_env,g_obj, g_mid);
if ((*g_env)->ExceptionCheck(g_env)) {
(*g_env)->ExceptionDescribe(g_env);
}
}
void initTimer() {
struct new_value;
struct sigaction action;
struct sigevent sev;
timer_t timerid;
/* Establish handler for timer signal */
action.sa_flags = SA_SIGINFO;
action.sa_sigaction = handler;
sigemptyset(&action.sa_mask);
if (sigaction(SIG1, &action, NULL) == -1)
__android_log_print(ANDROID_LOG_INFO, TAG, "sigaction");
/* Create the timer */
sev.sigev_notify = SIGEV_SIGNAL;
sev.sigev_signo = SIG1;
sev.sigev_value.sival_ptr = &timerid;
if (timer_create(CLOCK_MONOTONIC, &sev, &timerid) == -1)
__android_log_print(ANDROID_LOG_INFO, TAG, "timer_create");
/* Start the timer */
new_value.it_interval.tv_sec = 0;
new_value.it_interval.tv_nsec = 50*1000000; /* 50 ms*/
new_value.it_value.tv_sec = 0;
new_value.it_value.tv_nsec = 50*1000000; /* 50 ms */
if (timer_settime(timerid, 0, &new_value, NULL) == -1)
__android_log_print(ANDROID_LOG_INFO, TAG, "timer_settime");
}
JNIEXPORT void JNICALL Java_com_foo_MyJavaClass_register
(JNIEnv * env, jobject obj, jint delay) {
// convert local to global reference
// local will die after this method call
g_obj = (*env)->NewGlobalRef(env, obj);
// save refs for callback
jclass g_clazz = (*env)->GetObjectClass(env, g_obj);
if (g_clazz == NULL) {
}
g_mid = (*env)->GetMethodID(env, g_clazz, "callback", "()V");
if (g_mid == NULL) {
}
initTimer();
}
/***Java callback **/
public class MyJavaClass {
public void callback() {
Log.e("", "Java callback ");
}
public native void register(int delayInMs);
}
/*** Журнал Выходной ****/
09-06 05: 00: 45,430: I/(31763): Native обработчик
09-06 05: 00: 45,430: E/(31763): Java обратного вызова : : : 09-06 05: 00: 45,480: I/(31763): Native обработчик
09-06 05: 00: 45,480: E/(31763): Java обратный вызов 09-06 05: 00: 45.520: I/(31763): Родной обработчик
09-06 05: 00: 45.520: E/(31763): Обратный вызов Java 09-06 05: 00: 45.570: I/(31763): Родной обработчик
09-06 05: 00: 45.570: E/(31763): Обратный вызов Java 09-06 05: 00: 45.620: I/31763): Родной обработчик
09-06 05: 00: 45.620: E/(31763): Обратный вызов Java 09-06 05: 00: 45.680: I/(31763): Родной обработчик
09-06 05:00 : 45.680: E/(31763): Java callback 09-06 05: 00: 45.720: I/(31763): родной обработчик
09-06 05: 00: 45.770: I/(31763): родной обработчик
09-06 05: 00: 45.840: I/(31763): Родной обработчик
09-06 05: 00: 45.880: I/(31763): Родной обработчик
09-06 05: 00: 45.930: I/(31763): Родной обработчик 09-06 05: 00: 45.970: I/(31763): Собственный обработчик
09-06 05: 00: 46.030: I/31763): Родной обработчик
09-06 05: 00: 46,070: I/(31763): Native обработчик
09-06 05: 00: 46,130: I/(31763): Native обработчик
09-06 05: 00: 46.180: I/(31763): Родной обработчик
09-06 05: 00: 46.230: I/(31763): Родной обработчик
09-06 05: 00: 46.270: I/(31763): Нативный обработчик
09-06 05: 00: 46.330: I/(31763): родной обработчик
09-06 05: 00: 46.370: I/(31763): родной обработчик
Любая идея о том, как решить эту проблему? Спасибо заранее!
Из [Советы JNI от Google] (https://developer.android.com/training/articles/perf-jni.html): «Прикрепленные темы [с помощью' AttachCurrentThread'] ** должны вызывать ** 'DetachCurrentThread' * * до выхода **. " – Michael
Вы действительно вызываете методы Java из обработчика сигнала * *? ** Только ** [асинхронные сигнальные вызовы функций] (http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_04) можно безопасно сделать из обработчика сигнала. Все остальное, скорее всего, приведет к неопределенному поведению. –
Да @ Andrew. Я использую _signal handler_ для вызова java-метода. Я хотел, чтобы java-метод назывался точно в 50 мс. Есть ли лучший способ достичь этого? Если я использую сон в _pthread_, я наблюдаю, что java-метод не вызывается с точным интервалом 50 мс. – Autumn