最近遇到一個問題,在瘋狂點擊按鈕后胆绊,手機出現(xiàn)ANR
步驟一:通過查看ANR的log氨鹏,發(fā)現(xiàn)AudioTrack占用了將近100%的CPU
步驟二:分析AudioTrack的代碼
通過AudioTrack的PID,確認(rèn)到這個AudioTrack屬于system_server压状。
而這個AudioTrack是在播放按鈕的效果音仆抵。
步驟三:分析AudioTrack的代碼是否存在循環(huán)
bool AudioTrack::AudioTrackThread::threadLoop()
{
..................
if (mPaused) {
mMyCond.wait(mMyLock);
// caller will check for exitPending()
return true;
}
nsecs_t ns = mReceiver.processAudioBuffer();
...................
}
通過加log發(fā)現(xiàn),AudioTrack線程在threadLoop中瘋狂的循環(huán)种冬,這個就是導(dǎo)致CPU占用高的原因镣丑。我關(guān)閉掉系統(tǒng)效果音之后,ANR就沒法復(fù)現(xiàn)了碌廓。
理論上,這個threadLoop()會在mMyCond.wait停下來剩盒,但是現(xiàn)在沒有停下來谷婆,說明mPaused變量一直沒false,說明AudioTrack::stop函數(shù)一直沒有被調(diào)用辽聊。
步驟四:尋找AudioTrack::stop的入口
最后發(fā)現(xiàn)是在SoundPool.cpp的run函數(shù)中調(diào)用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;
}
那為什么沒有調(diào)用到channel->stop纪挎,最后分析發(fā)現(xiàn)卡在了mCondition.wait中,而通過分析發(fā)現(xiàn)下面函數(shù)的signal已經(jīng)調(diào)用了跟匆,但卻沒有喚醒
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占用過高了,導(dǎo)致喚醒非常地慢玛臂。當(dāng)然這個只是猜測烤蜕。
接下來能做什么?對比processAudioBuffer的流程迹冤。查看R狀態(tài)死鎖讽营。