当前位置: 首页 > 知识库问答 >
问题:

ART 可防止在本机信号处理期间从 JNI 进行任何 Java 调用

蒋奕
2023-03-14

我的项目在android系统中使用了一个捕获崩溃并发送的模块。当处理本机崩溃时,本机代码会做一些事情,然后从JNI进行java调用。它在Dalvik上运行良好。但在使用ART的android以上版本中就失效了,因为ART在原生信号处理过程中阻止了任何来自JNI的Java调用。上面说ART信号处理使用交替信号栈,所以在信号处理过程中,不能调用java方法?还有其他方法吗??< br >流量:< br> 1。Java调用本机方法,但本机方法崩溃。< br> 2。本机崩溃处理程序捕捉信号来处理崩溃。< br> 3。在崩溃处理过程中,调用JNI方法却失败了

12-31 20:36:02.516 7845-7957 A/art: art/runtime/check_jni.cc:65] JNI DETECTED ERROR IN APPLICATION: JNI IsSameObject called with pending exception 'java.lang.StackOverflowError' thrown in...
in call to IsSameObject
stack=0x9fff8000-0x9fffa000 stackSize=1036KB

参考:https://code.google.com/p/android/issues/detail?id=162663
如果有人从事艺术和/或仿生研究,那就太好了。

共有1个答案

汪耀
2023-03-14

您的项目依赖于未定义的行为。

任何信号处理程序都可以安全地只调用异步信号安全函数。任何其他函数调用都会调用未定义的行为。在任何情况下,依靠Java/Dalvik/ART虚拟机来限制自己进行异步信号安全的函数调用都是不现实的,而且很可能是不正确的。

可以随时调用任意信号的处理程序,使VM处于任何可能的状态。没有办法从JNI信号处理程序安全地进行Java调用,期望任何人甚至尝试支持此类调用也是不合理的-如果允许信号处理程序对同一对象进行调用,虚拟机的设计者如何允许信号中断任何同步的方法?如果他们这样做,就会违反<code>synchronized</code>的含义,从而破坏语言。但如果他们不这样做,他们会允许死锁,因为这样的调用会试图锁定一个永远无法解锁的对象,因为信号中断了处理。

简而言之,从信号处理程序通过JNI进行的Java调用从根本上是不受支持的。

他们曾经为你工作的事实只给了你一个期望,他们会继续这样做。

你过去很幸运。

它不再有效,你不能指望它在未来工作。

即使你以某种方式黑进它为你工作,它仍然从根本上是不健全的。根据POSIX标准,在信号处理程序中可以安全地进行的唯一调用是:

下表定义了一组功能,这些功能应是可重入的或不可被信号中断的,并且应是异步信号安全的。因此,应用程序可以不受限制地从信号捕获函数调用它们:

_Exit()
_exit()
abort()
accept()
access()
aio_error()
aio_return()
aio_suspend()
alarm()
bind()
cfgetispeed()
cfgetospeed()
cfsetispeed()
cfsetospeed()
chdir()
chmod()
chown()
clock_gettime()
close()
connect()
creat()
dup()
dup2()
execle()
execve()
fchmod()
fchown()
fcntl()
fdatasync()
fork()
fpathconf()
fstat()
fsync()
ftruncate()
getegid()
geteuid()
getgid()
getgroups()
getpeername()
getpgrp()
getpid()
getppid()
getsockname()
getsockopt()
getuid()
kill()
link()
listen()
lseek()
lstat()
mkdir()
mkfifo()
open()
pathconf()
pause()
pipe()
poll()
posix_trace_event()
pselect()
raise()
read()
readlink()
recv()
recvfrom()
recvmsg()
rename()
rmdir()
select()
sem_post()
send()
sendmsg()
sendto()
setgid()
setpgid()
setsid()
setsockopt()
setuid()
shutdown()
sigaction()
sigaddset()
sigdelset()
sigemptyset()
sigfillset()
sigismember()
sleep()
signal()
sigpause()
sigpending()
sigprocmask()
sigqueue()
sigset()
sigsuspend()
sockatmark()
socket()
socketpair()
stat()
symlink()
sysconf()
tcdrain()
tcflow()
tcflush()
tcgetattr()
tcgetpgrp()
tcsendbreak()
tcsetattr()
tcsetpgrp()
time()
timer_getoverrun()
timer_gettime()
timer_settime()
times()
umask()
uname()
unlink()
utime()
wait()
waitpid()
write()

上表中未列出的所有功能均被视为信号不安全。在存在信号的情况下,IEEE Std 1003.1-2001本卷中定义的所有功能在从信号捕捉功能调用或被信号捕捉功能中断时应按照定义的方式运行,只有一个例外:当信号中断不安全功能且信号捕捉功能呼叫不安全功能时,行为未定义。

由于无法保证从信号处理程序中通过JNI进行Java调用只会调用异步信号安全函数,因此除了未定义的行为之外,别无其他期望。

 类似资料:
  • 我实现了一个自定义POSIX信号处理程序参考:http://blog.httrack.com/blog/2013/08/23/catching-posix-signals-on-android/ 它们似乎是艺术的平台限制。 通过信号处理程序方法从JNI调用java方法,是否有变通方法或任何其他实现方法。 如果没有,那么是否有替代方案来捕获本机崩溃并传播到应用程序?

  • 问题内容: 我的理解是,通常来说,如果您从信号处理程序调用非异步信号安全函数,则行为是不确定的,但是我听说linux允许您安全地调用任何系统调用。这是真的?另外,SIGSEGV处理程序的唯一可移植行为是中止或退出,但是我知道如果您返回,Linux实际上将恢复执行,是吗? 问题答案: 我相信可以从信号处理程序中调用任何实际的系统调用。真实的系统调用中的数字为(或)。 手册页第2节中的某些posix函

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

  • 我正在使用Javaexec运行bash脚本,但当我进入CTRL C时,Java进程将退出,子进程也将退出,如何在JVM关闭后保持子进程运行? 父母亲上海: 我已经在这里和这里阅读了类似问题的答案,例如,使用nohup在脚本运行命令中启动父bash脚本,或者使用trap命令来阻止信号,在我的研究中,它可以工作,例如“tail-f somefile”,但不适用于我的用例“ffmpeg-params”,

  • 问题内容: 是否可以在Java虚拟机中处理POSIX信号? 至少SIGINT和SIGKILL应该完全独立于平台。 问题答案: JVM自行响应信号。有些会导致JVM正常关闭,其中包括运行关闭挂钩。其他信号将导致JVM在不运行关闭钩子的情况下中止。 关闭挂钩是使用Runtime.addShutdownHook(Thread)添加的。 我认为JDK没有提供处理Java应用程序中信号的正式方法。但是,我确

  • 问题内容: 我有一个独立的应用程序,在该应用程序中,我必须用确认对话框提示用户,以保存他尝试通过关闭系统时所做的更改。 我知道通过使用我们可以做到。 有人可以帮我如何使用信号处理程序吗 问题答案: 2012年5月更新(两年半后) Trejkaz评论: 在当前版本的Java上,此信号处理代码失败,因为“ ”信号“由VM或OS保留”。 此外,当某些东西要求关闭应用程序时,其他有效信号名称实际上都不会触