当前位置: 移动技术网 > IT编程>移动开发>Android > Android8.0平台Camera monkey拷机卡死异常解决方案

Android8.0平台Camera monkey拷机卡死异常解决方案

2018年11月01日  | 移动技术网IT编程  | 我要评论

北京公众出行网,发布租房信息,程毅君

android8.0平台camera monkey拷机卡死异常

最近在处理一个camera monkey拷机卡死的问题,卡死在停止录像的画面。

monkey测试命令

monkey -p com.android.camera2 --throttle 300 --ignore-crashes --ignore-timeouts --ignore-security-exceptions -v -v -v 50000000 &

camera卡住的时候,把mediaserver进程的backtrace打印可发现卡在audiosource::waitoutstandingencodingframes_l函数中,异常log:

debugger -b [pid]
...
[04-28 16:35:43]"binder:237_4" systid=2571
[04-28 16:35:43]  #00 pc 00018cd8  /system/lib/libc.so (syscall+28)
[04-28 16:35:43]  #01 pc 00047529  /system/lib/libc.so (__pthread_cond_timedwait(pthread_cond_internal_t*, pthread_mutex_t*, bool, timespec const*)+102)
[04-28 16:35:43]  #02 pc 000a7adb  /system/lib/libstagefright.so (android::audiosource::waitoutstandingencodingframes_l()+54)
[04-28 16:35:43]  #03 pc 000a787b  /system/lib/libstagefright.so (android::audiosource::reset()+82)
[04-28 16:35:43]  #04 pc 000a77e9  /system/lib/libstagefright.so (android::audiosource::~audiosource()+44)
[04-28 16:35:43]  #05 pc 000a794d  /system/lib/libstagefright.so (android::audiosource::~audiosource()+12)
[04-28 16:35:43]  #06 pc 0000ac5b  /system/lib/libutils.so (android::refbase::decstrong(void const*) const+70)
[04-28 16:35:43]  #07 pc 00049c4f  /system/lib/libmediaplayerservice.so (android::stagefrightrecorder::~stagefrightrecorder()+206)
[04-28 16:35:43]  #08 pc 00049e7b  /system/lib/libmediaplayerservice.so (android::stagefrightrecorder::~stagefrightrecorder()+2)
[04-28 16:35:43]  #09 pc 00047eef  /system/lib/libmediaplayerservice.so (android::mediarecorderclient::release()+34)
...

把调试log打开,并跟踪其代码流程如下

238 1538 v audiosource: set stoptime: 80223601 us
代码:
stagefrightrecorder.cpp
status_t stagefrightrecorder::stop() {
    int64_t stoptimeus = systemtime() / 1000;
    for (const auto &source : { maudioencodersource, mvideoencodersource }) {
        if (source != nullptr && ok != source->setstoptimeus(stoptimeus)) {
            alogw("failed to set stoptime %lld us for %s",
                    (long long)stoptimeus, source->isvideo() ? "video" : "audio");
        }
    }
audiosource.cpp
status_t audiosource::setstoptimeus(int64_t stoptimeus) {
    mstopsystemtimeus = stoptimeus;
    return ok;
}
238 1523 v audiosource: datacallbacktimestamp: 80264993 us
238 1523 v audiosource: drop audio frame at 80264993 stop time: 80223601 us
代码:
audiosource.cpp
    if (mstopsystemtimeus != -1 && timeus >= mstopsystemtimeus) {
        alogv("drop audio frame at %lld  stop time: %lld us",
                (long long)timeus, (long long)mstopsystemtimeus);
        mnomoreframestoread = true;
        mframeavailablecondition.signal();
        return ok;
    }
238 1538 i audiosource: read: mbuffersreceived is empty and mnomoreframestoread
代码
audiosource.cpp

status_t audiosource::read(
        mediabuffer **out, const readoptions * /* options */) {
    mutex::autolock autolock(mlock);
    *out = null;

    if (minitcheck != ok) {
        alogi("read: minitcheck not ok");
        return no_init;
    }

    while (mstarted && mbuffersreceived.empty()) {
        mframeavailablecondition.wait(mlock);
        if (mnomoreframestoread) {
            alogi("read: mbuffersreceived is empty and mnomoreframestoread");
            return ok;
        }
    }

此处当mbuffersreceived为空且mnomoreframestoread被设置时候,直接返回.

04-30 07:57:53.687 238 1538 v mediacodecsource: puller (audio) posting eos
04-30 07:57:53.730 238 1513 v mediacodecsource: puller (audio) reached eos
04-30 07:57:53.730 238 1513 v mediacodecsource: encoder (audio) reached eos
代码
mediacodecsource.cpp

         case kwhatpull:
             status_t err = msource->read(&mbuf);
             if (mbuf != null) {
                 mnotify->post();
                 msg->post();
             } else {
                 handleeos();
             }
mediacodecsource.cpp

 void mediacodecsource::puller::handleeos() {
     alogv("puller (%s) posting eos", misaudio ? "audio" : "video");
 //    android::callstack cs("puller::handleeos");
     sp msg = mnotify->dup();
     msg->setint32("eos", 1);
     msg->post();
 }

因为从source获取到的buffer为空,于是判定为eos,并进行eos处理。

04-30 07:57:54.126 238 1513 i mediacodecsource: encoder (audio) stopping
04-30 07:57:54.126 238 1513 i mediacodecsource: encoder (audio) already stopped
代码
mediacodecsource.cpp

     case kwhatstop:
     {
         alogi("encoder (%s) stopping", misvideo ? "video" : "audio");

         if (moutput.lock()->mencoderreachedeos) {
             // if we already reached eos, reply and return now
             alogi("encoder (%s) already stopped", 
                     misvideo ? "video" : "audio");
             (new amessage)->postreply(replyid);
             break;
         }
         mpuller->stop();

由于先前已经接收到eos信息,因此mediacodecsource在处理kwhatstop时候直接返回。

此次问题发生的流程大致如下

应用层发出停止录像的请求 audiosource把该停止录像的请求之后的音频数据丢弃,并设置mnomoreframestoread mediacodecsource从audiosource读取到buffer为null,于是判定为eos,并进行相关处理,但并不清除mediacodecsource::puller::queue.mreadbuffers mediacodecsource接收到kwhatstop消息,发现已经进行了eos处理,于是放弃执行puller.stop(它会对puller::queue.mreadbuffers执行flush操作),直接返回。 audiosource最后进行reset时候,调用waitoutstandingencodingframes_l去等待直到所有buffer被释放,但有些buffer在audio puller::queue.mreadbuffers没有释放,于是在进程被hold在此处。

暂时的修改方案是
在第4步处理kwhatstop消息时候,即使已经进行过eos处理,仍然执行puller.stop,以确保puller::queue.mreadbuffers为空。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网