SurfaceTexture中的野指针

当初遇到这个bug,是不定期的低概率出现,最后找到一个比较容易重现的步骤:

启动系统
然后进google +
 新建一个帐号(注意是新建一个帐号)
 没几步就重启了 

这个BUG,一开始追踪也是无头绪的,在这个bug出现时,系统的debuggerd还是有些问题,pt_regs设置的和内核对应不上,tombstone的信息完全无用,core dump功能也是无法使用,唯一的线索就是一点点logcat的trace, trace如下:

D/OpenGLRenderer( 2021): Flushing caches (mode 1)
D/OpenGLRenderer( 2021): Flushing caches (mode 0)
D/OpenGLRenderer( 1986): Flushing caches (mode 1)
W/SurfaceTexture( 1451): freeAllBuffersLocked called but mQueue is not empty
D/OpenGLRenderer( 1986): Flushing caches (mode 0)
F/libc    ( 1451): Fatal signal 11 (SIGSEGV) at 0x00000024 (code=1)
I/DEBUG   ( 1449): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
I/DEBUG   ( 1449): Build fingerprint: 'xxxx/IML74K/eng.freshui.20120213.154128:user/test-keys'
I/DEBUG   ( 1449): pid: 1451, tid: 1455  >>> /system/bin/surfaceflinger <<<
I/DEBUG   ( 1449): signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 00000024

重现时的错误,基本上都是类似的trace。 从此入手开始查找。 Trace中的一句话:

W/SurfaceTexture( 1451): freeAllBuffersLocked called but mQueue is not empty

是最大的怀疑目标,基于捉虫的经验,先做假定,已经可以解释出错的原因和现象了:

  •  mQueue通常是被两个模块使用的,一个enqueue,一个dequeue
  • 出错时,要将mQueue 给free掉,但mQueue不空,说明有人在用
  • 如果不管这个警告,强行将mQueue给free掉,极有可能造成另外一个模块使用被free掉的内存而引起段错误

转回头看代码,SurfaceTexture.cpp, 查一下mQueue的使用地方,哪里有出现free buffer的时候,mQueue 不为空的可能? 排查一下,还真找到了,看下这个函数:

 

status_t SurfaceTexture::setBufferCount(int bufferCount) {
    ST_LOGV("setBufferCount: count=%d", bufferCount);
    Mutex::Autolock lock(mMutex);

    if (mAbandoned) {
        ST_LOGE("setBufferCount: SurfaceTexture has been abandoned!");
        return NO_INIT;
    }
    if (bufferCount > NUM_BUFFER_SLOTS) {
        ST_LOGE("setBufferCount: bufferCount larger than slots available");
        return BAD_VALUE;
    }

    // Error out if the user has dequeued buffers
    for (int i=0 ; i<mBufferCount ; i++) {
        if (mSlots[i].mBufferState == BufferSlot::DEQUEUED) {
            ST_LOGE("setBufferCount: client owns some buffers");
            return -EINVAL;
        }
    }

    const int minBufferSlots = mSynchronousMode ?
            MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS;
    if (bufferCount == 0) {
        mClientBufferCount = 0;
        bufferCount = (mServerBufferCount >= minBufferSlots) ?
                mServerBufferCount : minBufferSlots;
        return setBufferCountServerLocked(bufferCount);
    }

    if (bufferCount < minBufferSlots) {
        ST_LOGE("setBufferCount: requested buffer count (%d) is less than "
                "minimum (%d)", bufferCount, minBufferSlots);
        return BAD_VALUE;
    }

    // here we're guaranteed that the client doesn't have dequeued buffers
    // and will release all of its buffer references.
    freeAllBuffersLocked();
    mBufferCount = bufferCount;
    mClientBufferCount = bufferCount;
    mCurrentTexture = INVALID_BUFFER_SLOT;
    mQueue.clear();
    mDequeueCondition.signal();
    return OK;
}


找到问题后,在freeAllBuffersLocked()调用之前,将mQueue给抽干一下,等使用的client都用完了再free就好了。

修改之后,再也没有碰到此类错误了。

当然此问题的排查和解决过程没这么顺利,也是搞了好几天的。 解决方法和问题原因也就不细说了,碰到并准备捉这个虫的同学应该会看明白的。

呵呵,这又是可以归结为 多线程同步/状态机 的问题,基本上目前我在Android碰到的严重问题都是这类了

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值