android - r17b - No se puede ejecutar JavaVM-> DetachCurrentThread(): "intentando separar mientras se está ejecutando el código"
ndk r13 (1)
Tengo una aplicación para Android que usa NDK, una aplicación Java estándar para Android con núcleo regular de UI y C ++. Hay lugares en el núcleo donde necesito llamar a los métodos Java, lo que significa que necesito un JNIEnv*
para ese hilo, lo que a su vez significa que necesito llamar a JavaVM->AttachCurrentThread()
para obtener el env
válido.
Previamente, solo estaba haciendo AttachCurrentThread
y no se molestó en separarlo. Funcionó bien en Dalvik, pero ART aborta la aplicación en cuanto sale un hilo que ha llamado a AttachCurrentThread
sin llamar a DetachCurrentThread
. Así que leí la referencia de JNI, y de hecho dice que debo llamar a DetachCurrentThread
. Pero cuando hago eso, ART aborta la aplicación con el siguiente mensaje:
intentando desconectarse mientras se ejecuta el código
¿Cuál es el problema aquí, y cómo llamar DetachCurrentThread
correctamente?
Dalvik también abortará si el hilo sale sin soltarse. Esto se implementa a través de una clave pthread - ver threadExitCheck()
en Thread.cpp .
Un hilo no puede separarse a menos que su pila de llamadas esté vacía. El razonamiento detrás de esto es garantizar que cualquier recurso como bloqueos de monitor (es decir, declaraciones synchronized
) se libere correctamente a medida que la pila se desenrolla.
La segunda y siguientes llamadas adjuntas son, como se define en la especificación, operaciones no operativas de bajo costo. No hay recuento de referencias, por lo que separar siempre se separa, sin importar cuántos agregados hayan sucedido. Una solución es agregar su propio contenedor contado por referencia.
Otro enfoque es adjuntar y separar cada vez. Esto es utilizado por el marco de aplicación en ciertas devoluciones de llamada. Esto no fue tanto una elección deliberada como un efecto secundario de envolver las fuentes de Java en torno al código desarrollado principalmente en C ++, y tratar de usar la funcionalidad en. Si miras SurfaceTexture.cpp , particularmente JNISurfaceTextureContext::onFrameAvailable()
, puede ver que cuando SurfaceTexture necesita invocar una función de devolución de llamada en lenguaje Java, adjuntará el hilo, invocará la devolución de llamada, y luego, si el hilo recién se adjuntó, lo separará inmediatamente. El distintivo "needsDetach" se establece llamando a GetEnv
para ver si el hilo se adjuntó anteriormente.
Esto no es una gran cosa en términos de rendimiento, ya que cada archivo adjunto necesita asignar un objeto Thread y hacer un mantenimiento interno interno de VM, pero produce el comportamiento correcto.