GC y onTouch causan un error de señal fatal 11 (SIGSEGV) en la aplicación que utiliza ffmpeg a través de ndk

Estoy recibiendo un error desagradable pero bien conocido mientras trabajaba con FFmpeg y NDK:

A/libc(9845): Fatal signal 11 (SIGSEGV), code 1, fault addr 0xa0a9f000 in tid 9921 (AsyncTask #4) 

ACTUALIZAR

Después de un par de horas descubrí que podría haber dos fuentes del problema. Uno de ellos estaba relacionado con el multithreading. Lo revisé y lo arreglé. Ahora la aplicación se bloquea SÓLO cuando la reproducción de vídeo (ndk) está activada.

Puse un "contador" en evento de contacto

  surfaceSterowanieKamera.setOnTouchListener(new View.OnTouchListener() { int counter = 0; @Override public boolean onTouch(View v, MotionEvent event) { if ((event.getAction() == MotionEvent.ACTION_MOVE)){ Log.i(TAG, "counter = " + counter); //cameraMover.setPanTilt(some parameters); counter++; } 

Y comencé a deshabilitar otras funcionalidades de la aplicación, una por una, pero sin vídeo. Me enteré de que, con cada sola funcionalidad menos, se tarda más tiempo para aplastar – contador alcanza valores más altos. Después de apagar todo aparte de la reproducción de vídeo y la interfaz táctil ( cameraMover.setPanTilt() comentado) la app aplastar normalmente cuando el contador está entre 1600 – 1700.

En tal caso, logcat muestra el error anterior y la información relacionada con GC. Para mí parece que GC está estropeando con el ndk.

 01-23 12:27:13.163: I/Display Activity(20633): n = 1649 01-23 12:27:13.178: I/art(20633): Background sticky concurrent mark sweep GC freed 158376(6MB) AllocSpace objects, 1(3MB) LOS objects, 17% free, 36MB/44MB, paused 689us total 140.284ms 01-23 12:27:13.169: A/libc(20633): Fatal signal 11 (SIGSEGV), code 1, fault addr 0x9bd6ec0c in tid 20734 (AsyncTask #3) 

¿Por qué el GC causa problemas con la parte ndk de la aplicación?


PROBLEMA ORIGINAL

¿Qué estoy haciendo?

Estoy desarrollando una aplicación que transmite la alimentación de video en vivo desde una cámara web y permite al usuario desplazar e inclinar la cámara remota. Estoy usando FFmpeg biblioteca construida con NDK para lograr una reproducción suave con poco retraso.

Estoy utilizando la biblioteca FFMpeg para conectarse a la secuencia de vídeo. A continuación, la parte ndk crea bitmap, realiza el procesamiento de imágenes y procesa marcos en el objeto SurfaceView videoSurfaceView que se encuentra en la actividad android (parte java).

Para mover la webcam he creado una clase separada – public class CameraMover implements Runnable{/**/} . Esta clase es un hilo separado que se conecta a través de sockets con la cámara remota y gestiona las tareas conectadas SOLAMENTE con movimiento de inclinación horizontal.

Luego en la actividad principal creé un oyente táctil

 videoSurfaceView.setOnTouchListener(new View.OnTouchListener() {/**/ cameraMover.setPanTilt(some parameters); /**/} 

Que lee el movimiento del dedo del usuario y envía comandos a la cámara.

Todas las tareas – mover la cámara, la interfaz táctil y la reproducción de vídeo funcionan perfectamente cuando el otro está desactivado, es decir, cuando desactivo la posibilidad de mover la cámara, puedo ver la transmisión de vídeo y registrar eventos táctiles hasta el final de los tiempos al menos). El problema se produce sólo cuando la tarea está configurada para funcionar simultáneamente.

No puedo encontrar pasos para reproducir el problema. Simplemente sucede, pero sólo después de que el usuario toque la pantalla para mover la cámara. Puede ser de 15 segundos después de la primera interacción, pero a veces tarda 10 minutos o más en fallar. Por lo general, es algo alrededor de un minuto.

¿Qué he hecho para arreglarlo?

  • He intentado mostrar millones de logs en logcat para encontrar un error, pero el último registro siempre fue diferente.
  • videoSurfaceView una superficie transparente, que puse sobre el videoSurfaceView y asignó el oyente de tacto a él. Todo terminó en el mismo error.
  • Como he mencionado antes, apagué algunas funcionalidades para encontrar que produce el error, pero parece que el error se produce sólo cuando todo está trabajando simultáneamente.

Tipos de error

Casi cada vez que el error se parece a esto:

 A/libc(11528): Fatal signal 11 (SIGSEGV), code 1, fault addr 0x9aa9f00c in tid 11637 (AsyncTask #4) 

La diferencia entre dos errores es el número justo después de libc, número de addr y número de tid. Raramente el número AsyncTask varía – recibí # 1 par de veces, pero no pude reproducirlo.

Pregunta

¿Cómo puedo evitar este error? ¿Cuál puede ser la fuente de ella?

El mensaje de error que citó, libc: Fatal signal 11 (SIGSEGV) , no dice mucho de lo que realmente sucedió – esto sólo dice que algo intentó acceder a la memoria (ya sea de lectura o escritura) incorrectamente. Puesto que se trata de un C api, podría ser casi cualquier cosa que está mal – cualquier uso de punteros, el uso de punteros que ya no son válidos, escribir demasiados datos en un buffer demasiado pequeño, etc

Por lo tanto, por desgracia, no da muchas pistas – sin ver el código C en cuestión, es imposible decir lo que puede causar esto.

Normalmente, el registro del dispositivo también contiene algún tipo de información de depuración que puede dar al menos una sugerencia vaga en donde ocurrió el error – vea, por ejemplo, la forma más fácil de depurar accidente en la biblioteca nativa, vinculado por la aplicación de Android? Para un ejemplo de esto. Esta publicación también contiene sugerencias sobre cómo habilitar CheckJNI para obtener una mejor información de depuración sobre el mal uso de las funciones JNI, que puede ser una causa de sus problemas. El NDK también contiene las herramientas ndk-stack y ndk-gdb que pueden usarse para obtener información más precisa sobre dónde se produce el bloqueo.

Tenga en cuenta que incluso si se obtiene un punto preciso de dónde se produce el accidente, que no puede apuntar directamente a donde está el error en el código.

En este caso, cuando usted dice que parece que el GC está causando, me suena como si estuviera mal uso de objetos java a través de JNI – como si está manteniendo referencias a objetos java sin mantener las referencias correctamente a través de JNI. Cuando se ejecuta el GC, puede mover los datos asignados alrededor, asumiendo que nadie está manteniendo apuntadores directos a él.

Vea http://android-developers.blogspot.com/2011/07/debugging-android-jni-with-checkjni.html para más información sobre lo que podría ser.

Puede encontrar un error utilizando la dirección de fallo

Utilice debajo del comando para encontrar el error utilizando la dirección de falla. Yo uso este comando en la máquina MAC. En su caso, la dirección de error es 0xa0a9f000 0x9aa9f00c

Como he encontrado de su pregunta, lo que el uso de la dirección de la falta en debajo de comando utilice será capaz de encontrar la causa real.

Usando este comando puede encontrar la causa real de la señal fatal.

 ./arm-linux-androideabi-addr2line -C -f -e <Here is the Path of your .so file> <Here is the fault address> 

En mi caso, utilizo el comando below, estoy usando cocos2dX de esa manera me refiero libcocos2dcpp.so archivo libcocos2dcpp.so

 ./arm-linux-androideabi-addr2line -C -f -e /Volumes/Data_HD/Android/cocos2d-x-2.2.2/projects/Rummy/proj.android/obj/local/armeabi-v7a/libcocos2dcpp.so 00000000 

El problema real para causar la señal fatal es que se están refiriendo a ese objeto que la referencia es clara por GC. O puede ser que hay un problema JNI.

FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.