Android:播放系统效果音导致ANR问题分析

最近遇到一个问题,在疯狂点击按钮后,手机出现ANR

步骤一:通过查看ANR的log,发现AudioTrack占用了将近100%的CPU

步骤二:分析AudioTrack的代码

通过AudioTrack的PID,确认到这个AudioTrack属于system_server。
而这个AudioTrack是在播放按钮的效果音。

步骤三:分析AudioTrack的代码是否存在循环

bool AudioTrack::AudioTrackThread::threadLoop()
{
    ..................
        if (mPaused) {
            mMyCond.wait(mMyLock);
            // caller will check for exitPending()
            return true;
        }
    nsecs_t ns = mReceiver.processAudioBuffer();
   ...................
}

通过加log发现,AudioTrack线程在threadLoop中疯狂的循环,这个就是导致CPU占用高的原因。我关闭掉系统效果音之后,ANR就没法复现了。
理论上,这个threadLoop()会在mMyCond.wait停下来,但是现在没有停下来,说明mPaused变量一直没false,说明AudioTrack::stop函数一直没有被调用。

步骤四:寻找AudioTrack::stop的入口

最后发现是在SoundPool.cpp的run函数中调用stop的

int SoundPool::run()
{
    mRestartLock.lock();
    while (!mQuit) {
        mCondition.wait(mRestartLock);
        ALOGV("awake");
        if (mQuit) break;
        while (!mStop.empty()) {
            SoundChannel* channel;
            ALOGV("Getting channel from stop list");
            List::iterator iter = mStop.begin();
            channel = *iter;
              this, channel->mChannelID);
            mStop.erase(iter);
            mRestartLock.unlock();
            if (channel != 0) {
                Mutex::Autolock lock(&mLock);
                channel->stop();   //这里去stop
            }
            mRestartLock.lock();
            if (mQuit) break;
        }

        while (!mRestart.empty()) {
            SoundChannel* channel;
            ALOGV("Getting channel from list");
            List::iterator iter = mRestart.begin();
            channel = *iter;
            mRestart.erase(iter);
            mRestartLock.unlock();
            if (channel != 0) {
                Mutex::Autolock lock(&mLock);
                channel->nextEvent();
            }
            mRestartLock.lock();
            if (mQuit) break;
        }
    }
    mStop.clear();
    mRestart.clear();
    mCondition.signal();
    mRestartLock.unlock();
    ALOGV("goodbye");
    return 0;
}

那为什么没有调用到channel->stop,最后分析发现卡在了mCondition.wait中,而通过分析发现下面函数的signal已经调用了,但却没有唤醒

void SoundPool::addToStopList(SoundChannel* channel)
{
    Mutex::Autolock lock(&mRestartLock);
    if (!mQuit) {
        mStop.push_back(channel);
        mCondition.signal();
        KPOC_LOGE("addToStopList.signal mQuit= %d",mQuit);
    }
}

这种情况,我分析是cpu占用过高了,导致唤醒非常地慢。当然这个只是猜测。

接下来能做什么?对比processAudioBuffer的流程。查看R状态死锁。

你可能感兴趣的:(Android:播放系统效果音导致ANR问题分析)