ART предотвращает любые вызовы Java из JNI во время собственной обработки сигналов.

В моем проекте используется модуль фиксации сбоя и отправки в систему Android. При обработке собственного сбоя собственный код что-то делает, а затем выполняет вызовы Java из JNI. Хорошо работает на Далвике. Но это не работает в версии Android выше 5.0 с использованием ART. Потому что ART предотвращает любые вызовы Java из JNI во время собственной обработки сигналов. В нем говорится, что обработка сигналов ART использует альтернативный стек сигналов, поэтому в процессе обработки сигналов нельзя вызывать java-методы? Есть ли другие способы ??
Flow :
1. Java вызывает собственный метод, но собственный метод дает сбой.
2. Встроенный обработчик сбоев улавливает сигнал для обработки сбоя.
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
Было бы неплохо, если бы кто-нибудь, работающий с ART и / или Bionic, мог изучить это.


person sduMonkey    schedule 31.12.2015    source источник
comment
Почему вы используете термин «сигнал»? На первый взгляд, вы спрашиваете об обработке исключений в JNI. Поведение ART является законным, см. developer.android.com/training/articles/   -  person Alex Cohn    schedule 01.01.2016
comment
Я использую обработчик сигналов, чтобы поймать и записать сбой в процессе собственных вызовов, а не сосредоточиться на процессе JNI.   -  person sduMonkey    schedule 03.01.2016
comment
Обратите внимание, что Crashlytics действительно сохраняет трассировку стека для (некоторых) родной вылетает. Они делают все возможное, чтобы развернуть стек вызовов (даже не вызывая JVM), и часто это дает значимую информацию, которая может помочь исправить ситуацию в будущем. Они отправляют дамп на свой сервер при следующем вызове приложения, что имеет смысл на Android: здесь система немедленно перезапустит приложение, которое вылетело по какой-либо причине, хотя бы один раз.   -  person Alex Cohn    schedule 12.08.2018


Ответы (1)


Ваш проект полагается на неопределенное поведение.

Любой обработчик сигналов может безопасно выполнять только вызовы асинхронных сигнально-безопасных функций. Любой другой вызов функции вызывает неопределенное поведение. Полагаться на виртуальную машину Java / Dalvik / ART для ограничения себя вызовами функций, безопасных для асинхронных сигналов, в любой ситуации в лучшем случае нереально и, скорее всего, просто неверно.

Ваш обработчик произвольного сигнала может быть вызван в любое время, оставив виртуальную машину в любом возможном состоянии. Невозможно безопасно выполнять вызовы Java из обработчика сигналов JNI, и неразумно ожидать, что кто-то даже попытается поддержать такие вызовы - как могут конструкторы виртуальной машины разрешить сигналу прерывать любой метод synchronized, если обработчику сигнала было разрешено совершать вызовы synchronized на том же объекте? Если бы они сделали это, они бы нарушили язык, нарушив само значение synchronized. Но если бы они этого не сделали, они разрешили бы взаимоблокировки, поскольку такие вызовы будут пытаться заблокировать объект, который никогда не может быть разблокирован, потому что сигнал прервал обработку.

Короче говоря, вызовы Java через JNI из обработчика сигналов принципиально не поддерживаются.

Тот факт, что раньше они работали на вас, только давал вам надежду на то, что они будут продолжать это делать.

Тебе раньше везло.

Он больше не работает, и вы не можете ожидать, что он будет работать в будущем.

И даже если вы каким-то образом заставите его работать на себя, это все равно фундаментально несостоятельно. Единственные безопасные вызовы из обработчика сигналов согласно стандарту 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, должны вести себя так, как определено, когда вызываются из или прерываются функцией перехвата сигналов, за одним исключением: когда сигнал прерывает небезопасную функцию и сигнал- функция перехвата вызывает небезопасную функцию, поведение не определено.

Поскольку вы не можете гарантировать, что вызов Java через JNI из обработчика сигналов будет вызывать только асинхронные сигнально-безопасные функции, вы не можете ожидать чего-либо, кроме неопределенного поведения.

person Andrew Henle    schedule 01.01.2016