ART 在本机信号处理期间阻止来自 JNI 的任何 Java 调用

ART prevents any Java calls from JNI during native signal handling

我的项目在android系统中使用了捕获崩溃并发送的模块。处理本机崩溃时,本机代码将执行某些操作,然后执行来自 JNI 的 java 调用。它在 Dalvik 上运行良好。但它在 android 5.0 以上的版本中使用 ART 失败。因为 ART 在本机信号处理期间阻止来自 JNI 的任何 Java 调用。上面写着ART信号处理使用alternate signal stack,那么在信号处理的过程中,不能调用java方法吗?还有其他方法吗??
流量:
1. Java调用native方法,native方法崩溃
2. 本机崩溃处理程序捕获信号以处理崩溃。
3. crash处理过程中调用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.WhosebugError' thrown in...
in call to IsSameObject
stack=0x9fff8000-0x9fffa000 stackSize=1036KB

参考:https://code.google.com/p/android/issues/detail?id=162663
如果使用 ART and/or Bionic 的人可以对此进行调查,那就太好了。

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

任何信号处理程序都可以安全地调用async-signal-safe函数。任何其他函数调用都会调用未定义的行为。在任何情况下依赖 Java/Dalvik/ART 虚拟机将自身限制为 async-signal-safe 函数调用充其量是不现实的,很可能只是不正确的。

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

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

他们曾经为您工作的事实只会让您期望他们会继续这样做。

你过去很幸运。

它不再起作用,你不能指望它在未来起作用。

即使您以某种方式破解它为您工作,它仍然根本不健全。根据 the POSIX standard,从信号处理程序中可以安全进行的唯一调用是:

The following table defines a set of functions that shall be either reentrant or non-interruptible by signals and shall be async-signal-safe. Therefore applications may invoke them, without restriction, from signal-catching functions:

_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()

All functions not in the above table are considered to be unsafe with respect to signals. In the presence of signals, all functions defined by this volume of IEEE Std 1003.1-2001 shall behave as defined when called from or interrupted by a signal-catching function, with a single exception: when a signal interrupts an unsafe function and the signal-catching function calls an unsafe function, the behavior is undefined.

因为你无法保证从信号处理程序中通过 JNI 进行 Java 调用只会调用 async-signal-safe 函数,所以你无法期待任何事情但未定义的行为。