最近遇到一个问题,在疯狂点击按钮后,手机出现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<SoundChannel* >::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<SoundChannel*>::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状态死锁。