【问题标题】:ART prevents any Java calls from JNI during native signal handlingART 在本机信号处理期间防止来自 JNI 的任何 Java 调用
【发布时间】:2016-04-05 11:18:43
【问题描述】:

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

参考:https://code.google.com/p/android/issues/detail?id=162663
如果有人使用 ART 和/或 Bionic 可以调查一下,那就太好了。

【问题讨论】:

  • 您为什么使用术语“信号”?从表面上看,您是在询问exception handling in JNI。 ART 行为合法,见developer.android.com/training/articles/…
  • 我使用signal handler来捕捉和记录native调用过程中的crash,而不是关注JNI的过程。
  • 请注意,Crashlytics 确实保留了 (some) 本机崩溃的堆栈跟踪。他们尽最大努力展开调用堆栈(无需调用 JVM),这通常会提供有意义的信息,有助于解决未来的情况。他们在下一次调用应用程序时将转储发送到服务器,这在 Android 上非常有意义:在这里,系统将立即重新启动因任何原因崩溃的应用程序,至少一次。

标签: android exception-handling java-native-interface native-code


【解决方案1】:

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

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

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

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

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

过去你很幸运。

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

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

下表定义了一组函数,它们应为 可重入或不可被信号中断,并且应 异步信号安全。因此应用程序可以调用它们,而无需 限制,来自信号捕捉功能:

_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 调用只会调用异步信号安全函数,因此除了未定义的行为之外,您无法期待任何事情。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-13
    • 1970-01-01
    • 2010-09-07
    相关资源
    最近更新 更多