GC和onTouch在使用ffmpeg到ndk的应用程序中导致致命信号11(SIGSEGV)错误

时间:2015-01-20 16:52:55

标签: android android-ndk ffmpeg ontouchlistener sigsegv

在使用FFmpeg和NDK时,我遇到了一个令人讨厌但却众所周知的错误:

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

更新

几个小时后,我发现可能有两个问题来源。一个与多线程有关。我查了一下,然后修好了。现在,只有在视频播放(ndk)开启时,应用程序才会崩溃。

我把一个"计数器"触摸事件

  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++;
                 }

我开始逐个禁用其他应用功能,但没有视频。我发现,每减少一个功能,压缩需要更长的时间 - 计数器达到更高的值。关闭视频播放和触摸界面(cameraMover.setPanTilt()注释掉)以外的所有内容后,当计数器介于1600 - 1700之间时,应用程序通常会崩溃。

在这种情况下,logcat显示上述错误和GC相关信息。对我而言,似乎GC正在搞乱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)

为什么GC导致ndk部分应用程序出现问题?


原始问题

我在做什么?

我正在开发一个应用程序,可以从网络摄像头流式传输实时视频,并允许用户平移和倾斜远程摄像头。我正在使用用NDK构建的FFmpeg库来实现流畅播放,几乎没有延迟。

我正在使用FFMpeg库连接到视频流。然后ndk部分创建位图,对位于android活动(java部分)中的SurfaceView videoSurfaceView对象进行图像处理和渲染帧。

要移动网络摄像头,我创建了一个单独的类 - public class CameraMover implements Runnable{/**/}。此类是一个单独的线程,通过套接字与远程摄像头连接,并管理仅通过云台移动连接的任务。

接下来在主要活动中我创建了一个触控监听器

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

读取用户的手指移动并向相机发送命令。

所有任务 - 移动相机,触摸界面和视频播放在其他人被禁用时工作正常,即当我禁用移动相机的可能性时,我可以观看视频流和注册触摸事件直到时间结束(或至少电池)。 仅当任务配置为同时工作时才会出现此问题。

我无法找到重现问题的步骤。它只是发生,但只有在用户触摸屏幕移动相机后。它可以在第一次交互后15秒,但有时需要10分钟或更长时间才能崩溃。通常这是一分钟左右。

我做了什么修复?

  • 我试图在logcat中显示数百万个日志以查找错误但是 最后一个日志总是不同。
  • 我创建了一个透明的表面,我将videoSurfaceView放在上面,并为其分配了触摸侦听器。这一切都以同样的错误结束。
  • 正如我之前提到的,我关闭了一些功能,以找出哪一个产生错误,但似乎只有当一切都同时工作时才会发生错误。

错误类型

几乎每次错误都是这样的:

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

两个错误之间的差异是libc,addr number和tid number之后的数字。很少AsyncTask号码变化 - 我收到了#1几次,但我无法重现它。

问题

如何避免此错误?它可能是什么来源?

2 个答案:

答案 0 :(得分:8)

您引用的错误消息libc: Fatal signal 11 (SIGSEGV)并未说明实际发生的事情 - 这只是说某些内容试图错误地访问内存(读取或写入)。由于这是一个C api,它可能只是任何错误 - 使用指针,使用不再有效的指针,将太多数据写入太小的缓冲区等等。

所以很遗憾没有提供太多线索 - 如果没有看到相关的C代码,就不可能说出导致这种情况的原因。

通常,设备日志还包含某种调试信息,这些信息至少可以提供错误发生位置的模糊提示 - 请参阅例如easiest way to debug crash in native library, linked by Android app?以此为例。这篇文章还包含有关启用CheckJNI以获得有关滥用JNI函数的更好调试信息的提示,这可能是导致问题的原因之一。 NDK还包含工具ndk-stackndk-gdb,可用于获取有关崩溃发生位置的更准确信息。

请注意,即使您准确了解崩溃发生的位置,也可能无法直接指出代码中的错误位置。

在这种情况下,当你说它似乎是GC导致它时,听起来像是你通过JNI滥用java对象 - 好像你保持对java对象的引用而不通过JNI正确保存引用。当GC运行时,它可以移动分配的数据,假设没有人保持直接指向它。

请参阅http://android-developers.blogspot.com/2011/07/debugging-android-jni-with-checkjni.html以获取更多关于它可能的提示。

答案 1 :(得分:0)

您可以使用故障地址

找到错误

使用以下命令查找使用故障地址的错误。 我在MAC机器上使用此命令。 在您的情况下,故障地址为0xa0a9f000 0x9aa9f00c

正如我从你的问题中发现的那样,无论在下面的命令使用中使用哪个故障地址都能找到实际原因。

使用此命令可以找到致命信号的实际原因。

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

在我的情况下,我使用下面的命令,我使用的是cocos2dX,这就是我所指的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

导致致命信号的实际问题是你所指的那个对象哪个参考通过GC清除。或者可能存在JNI问题。