Android和JNI实时时钟 [英] Android and JNI real time clock

查看:190
本文介绍了Android和JNI实时时钟的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到了一个小型Android应用程序的问题,并且在 C(JNI)函数中使用了实时时钟信号.

I got a problem with a mini Android application and the use of real time clock signals in a C (JNI) function.

Android UI似乎不喜欢来自C函数中实例化的计时器的实时信号.

It seems like Android UI doesn't like real time signals from timers instanced in a C function.

在下面的PoC中,计时器每秒触发一次信号5次,如果在更新UI时触发了该信号,则应用程序将崩溃.

In the following PoC, a timer trigger a signal 5 times per second and if the signal is triggered while the UI is updating, the application crashes.

  • 如果我不启动计时器=>没有崩溃
  • 如果我不在UI上放任何东西=>不会崩溃

我写了这个小的PoC来证明这种行为. Java部分只需调用JNI函数并在屏幕上放置一个按钮即可.

I wrote this little PoC to evidence the behaviour. Java part just call the JNI function and put a button on screen.

public class MainActivity extends AppCompatActivity {

    Button bt;

    static {
        System.loadLibrary("testtimer-jni");
    }

    /* JNI ingresso */
    public native void jniStartTimer();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        jniStartTimer();

        /* load button */
        bt = new Button(getBaseContext());

        setContentView(bt);
    }
}    

,这是main.c文件的内容.计时器被实例化并启动.每200ms次(每秒5次)cb()函数都会被调用.

and this is the main.c file content. A timer is instanced and started. Every 200ms (5 times per sec) the cb() function is called.

#include <jni.h>
#include <android/log.h>
#include <signal.h>
#include <time.h>
#include <strings.h>

timer_t           timer_id = 0x12;
struct itimerspec timer;
struct sigevent   te;
struct sigaction  sa;

void cb(int sig, siginfo_t *si, void *uc)
{
    __android_log_write(ANDROID_LOG_ERROR, "Test", "Called callback");
}

void Java_it_dbtecno_testtimer_MainActivity_jniStartTimer(JNIEnv *env, jobject thiz)
{
    __android_log_write(ANDROID_LOG_ERROR, "Test", "Timer inited");

    /* prepare timer to emulate video refresh interrupts */
    sa.sa_flags = SA_SIGINFO;
    sa.sa_sigaction = cb;
    sigemptyset(&sa.sa_mask);

    if (sigaction(SIGRTMIN + 7, &sa, NULL) == -1)
        return;
    bzero(&te, sizeof(struct sigevent));

    /* set and enable alarm */
    te.sigev_notify = SIGEV_SIGNAL;
    te.sigev_signo = SIGRTMIN + 7;
    te.sigev_value.sival_ptr = &timer_id;
    timer_create(CLOCK_REALTIME, &te, &timer_id);

    timer.it_value.tv_sec = 1;
    timer.it_value.tv_nsec = 1000;
    timer.it_interval.tv_sec = 0;
    timer.it_interval.tv_nsec = 1000000000 / 5;

    /* start timer */
    timer_settime(timer_id, 0, &timer, NULL);
}

有时它会立即死亡,有时会在我按下按钮后死亡(我认为这取决于信号/UI更新的时间)并将其输出到日志中

Sometimes it dies instantly, sometimes it dies after i press the button (i think it depends on timing of signal/UI update) and it output this on log

09-22 11:52:12.087 13587-13587/it.dbtecno.testtimer I/Test: Called callback
09-22 11:52:12.288 13587-13587/it.dbtecno.testtimer I/Test: Called callback
09-22 11:52:12.501 13587-13587/it.dbtecno.testtimer I/Test: Called callback
09-22 11:52:12.532 13587-13587/it.dbtecno.testtimer A/OpenGLRenderer: Task is already in the queue!
09-22 11:52:12.532 13587-13587/it.dbtecno.testtimer A/libc: Fatal signal 6 (SIGABRT), code -6 in tid 13587 (tecno.testtimer)
09-22 11:52:12.637 1187-1187/? A/DEBUG: *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
09-22 11:52:12.637 1187-1187/? A/DEBUG: Build fingerprint: 'Android/sdk_google_phone_x86/generic_x86:6.0/MASTER/3079352:userdebug/test-keys'
09-22 11:52:12.637 1187-1187/? A/DEBUG: Revision: '0'
09-22 11:52:12.637 1187-1187/? A/DEBUG: ABI: 'x86'
09-22 11:52:12.638 1187-1187/? A/DEBUG: pid: 13587, tid: 13587, name: tecno.testtimer  >>> it.dbtecno.testtimer <<<
09-22 11:52:12.638 1187-1187/? A/DEBUG: signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------
09-22 11:52:12.642 1187-1187/? A/DEBUG: Abort message: 'Task is already in the queue!'
09-22 11:52:12.642 1187-1187/? A/DEBUG:     eax 00000000  ebx 00003513  ecx 00003513  edx 00000006
09-22 11:52:12.642 1187-1187/? A/DEBUG:     esi b77a5c50  edi 0000000b
09-22 11:52:12.642 1187-1187/? A/DEBUG:     xcs 00000073  xds 0000007b  xes 0000007b  xfs 00000007  xss 0000007b
09-22 11:52:12.642 1187-1187/? A/DEBUG:     eip b736f666  ebp 00003513  esp bfdc7540  flags 00200202
09-22 11:52:12.644 1187-1187/? A/DEBUG: backtrace:
09-22 11:52:12.645 1187-1187/? A/DEBUG:     #00 pc 00084666  /system/lib/libc.so (tgkill+22)
09-22 11:52:12.650 1187-1187/? A/DEBUG:     #01 pc 00081608  /system/lib/libc.so (pthread_kill+70)
09-22 11:52:12.651 1187-1187/? A/DEBUG:     #02 pc 00027205  /system/lib/libc.so (raise+36)
09-22 11:52:12.651 1187-1187/? A/DEBUG:     #03 pc 000209e4  /system/lib/libc.so (abort+80)
09-22 11:52:12.659 1187-1187/? A/DEBUG:     #04 pc 0000cbc3  /system/lib/libcutils.so (__android_log_assert+128)
09-22 11:52:12.660 1187-1187/? A/DEBUG:     #05 pc 00025e81  /system/lib/libhwui.so (android::uirenderer::renderthread::RenderThread::queue(android::uirenderer::renderthread::RenderTask*)+81)
09-22 11:52:12.660 1187-1187/? A/DEBUG:     #06 pc 00021b44  /system/lib/libhwui.so
09-22 11:52:12.660 1187-1187/? A/DEBUG:     #07 pc 000243e5  /system/lib/libhwui.so (android::uirenderer::renderthread::RenderProxy::syncAndDrawFrame()+29)
09-22 11:52:12.660 1187-1187/? A/DEBUG:     #08 pc 000ba75b  /system/lib/libandroid_runtime.so
09-22 11:52:12.660 1187-1187/? A/DEBUG:     #09 pc 72dfe20e  /data/dalvik-cache/x86/system@framework@boot.oat (offset 0x1eb2000)
09-22 11:52:12.713 1187-1187/? A/DEBUG: Tombstone written to: /data/tombstones/tombstone_08
09-22 11:52:12.713 1187-1187/? E/DEBUG: AM write failed: Broken pipe

我也尝试更改信号编号(从SIGRTMIN更改为SIGRTMIN + 20),但是没有运气....

I also tried to change the signal number (from SIGRTMIN to SIGRTMIN + 20) but no luck....

我的问题是....是否可以在不破坏RenderThread的情况下在JNI函数中使用实时时钟信号? (是的,后者崩溃了)

My question is.... Is it possible to use real time clock signals in a JNI function without breaking the RenderThread? (Yes, it's the latter that crashes)

在JNI函数中使用计时器是否有坏习惯?

Is it a bad habit to play with timers in JNI functions?

推荐答案

计时器信号可能传递到了渲染器线程或主线程.在这种情况下,它将中断该线程(如果有)中正在进行的系统调用.这种情况可能会在运行时代码中触发一些断言.您可以玩SIGEV_THREAD_ID将信号定向到专用线程.但是请注意,此通知类型不适用于广泛使用.同样,一些实时信号可能会被仿生线程实现甚至ART静默使用.因此,很容易破坏某些东西.

Probably timer signal is delivered to renderer thread or main thread. In such case it interrupts system call that is in progress in that thread (if any). And this situation may trigger some assert in runtime code. You may play with SIGEV_THREAD_ID to direct signal to dedicated thread. But be aware that this notification type is not intended for widespread usage. Also some of real-time signals may be silently used by bionic threading implementation or even ART. So it is very easy to break something.

P.S.如果可能的话-您应该选择SIGEV_THREAD.由于您不应该考虑适当的信号编号等,因此它在Android上看起来更可靠.

P.S. if possible - you should prefer SIGEV_THREAD. It looks more reliable on Android since you shouldn't think about proper signal numbers etc.

这篇关于Android和JNI实时时钟的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆