圖7-5中說明的AT和AF交互的流程,對于分析AF來說非常重要。先來回顧一下圖7-5的流程:
- AT調用createTrack,得到一個IAudioTrack對象。
- AT調用IAudioTrack對象的start,表示準備寫數據了。
- AT通過write寫數據,這個過程和audio_track_cblk_t有著密切關系。
- 最后AT調用IAudioTrack的stop或delete IAudioTrack結束工作。
至此,上面的每一步都很清楚了。根據Binder知識,AT調用的這些函數最終都會在AF端得到實現,所以可直接從AF端開始。
1. createTrack的分析
按照前面的流程步驟,第一個被調用的函數會是createTrack,請注意在用例中傳的參數。
**AudioFlinger.cpp**
~~~
sp<IAudioTrack> AudioFlinger::createTrack(
pid_t pid,//AT的pid號
int streamType,//流類型,用例中是MUSIC類型
uint32_t sampleRate,//8000 采樣率
int format,//PCM_16類型
int channelCount,//2,雙聲道
int frameCount,//需要創建緩沖的大小,以幀為單位
uint32_t flags,
const sp<IMemory>& sharedBuffer,//AT傳入的共享buffer,這里為空
int output,//這個值前面提到過,是AF中的工作線程索引號
status_t *status)
{
sp<PlaybackThread::Track> track;
sp<TrackHandle> trackHandle;
sp<Client> client;
wp<Client>wclient;
status_t lStatus;
{
Mutex::Autolock _l(mLock);
//output代表索引號,這里根據索引號找到一個工作線程,它是一個PlaybackThread
PlaybackThread *thread = checkPlaybackThread_l(output);
//看看這個進程是否已經是AF的Client,AF根據進程pid來標識不同的Client
wclient = mClients.valueFor(pid);
if(wclient != NULL) {
}else {
//如果還沒有這個Client信息,則創建一個,并加入到mClients中去
client = new Client(this, pid);
mClients.add(pid, client);
}
//在找到的工作線程對象中創建一個Track,注意它的類型是Track
track = thread->createTrack_l(client, streamType, sampleRate, format,
channelCount, frameCount, sharedBuffer, &lStatus);
}
/*
TrackHandle是Track對象的Proxy,它支持Binder通信,而Track不支持Binder
TrackHandle所接收的請求最終會由Track處理,這是典型的Proxy模式
*/
trackHandle= new TrackHandle(track);
returntrackHandle;
}
~~~
這個函數相當復雜,主要原因之一,是其中出現了幾個我們沒接觸過的類。我剛接觸這個函數的時候,大腦也曾因看到這些眼生的東西而“死機”!不過暫時先不用去理會它們,等了解了這個函數后,再回過頭來收拾它們。先進入checkPlaybackThread_l看看。
(1) 選擇工作線程
checkPlaybackThread_l的代碼如下所示:
**AudioFlinger.cpp**
~~~
AudioFlinger::PlaybackThread *
AudioFlinger::checkPlaybackThread_l(intoutput) const
{
PlaybackThread*thread = NULL;
//根據output的值找到對應的thread
if(mPlaybackThreads.indexOfKey(output) >= 0) {
thread = (PlaybackThread *)mPlaybackThreads.valueFor(output).get();
}
returnthread;
}
~~~
上面函數中傳入的output,就是之前在分析AT時提到的工作線程索引號。看到這里,是否感覺有點困惑?困惑的原因可能有二:
- 目前的流程中尚沒有見到創建線程的地方,但在這里確實能找到一個線程。
- Output含義到底是什么?為什么會把它作為index來找線程呢?
關于這兩個問題,待會兒再做解釋。現在只需知道AudioFlinger會創建幾個工作線程,AT會找到對應的工作線程即可。
(2) createTrack_l的分析
找到工作線程后,會執行createTrack_l函數,請看這個函數的作用:
**AudioFlinger.cpp**
~~~
// Android的很多代碼都采用了內部類的方式進行封裝,看習慣就好了
sp<AudioFlinger::PlaybackThread::Track>
AudioFlinger::PlaybackThread::createTrack_l(
const sp<AudioFlinger::Client>& client,int streamType,
uint32_tsampleRate,int format,int channelCount,int frameCount,
const sp<IMemory>& sharedBuffer,//注意這個參數,從AT中傳入,為0
status_t *status)
{
sp<Track> track;
status_t lStatus;
{
Mutex::Autolock _l(mLock);
//創建Track對象
track= new Track(this, client, streamType, sampleRate, format,
channelCount, frameCount,sharedBuffer);
//將新創建的Track加入到內部數組mTracks中
mTracks.add(track);
}
lStatus= NO_ERROR;
returntrack;
}
~~~
上面的函數調用傳入的sharedBuffer為空,那共享內存又是在哪里創建的呢?可以注意到Track構造函數關于sharedBuffer這個參數的類型是一個引用,莫非是構造函數創建的?
(3) Track創建共享內存和TrackHandle
在createTrack_l中,會new出來一個Track,請看它的代碼:
**AudioFlinger.cpp**
~~~
AudioFlinger::PlaybackThread::Track::Track(const wp<ThreadBase>& thread,
const sp<Client>& client,int streamType,uint32_t sampleRate,
int format,int channelCount,int frameCount,
const sp<IMemory>& sharedBuffer)
: TrackBase(thread, client, sampleRate, format, channelCount,
frameCount,0, sharedBuffer),//sharedBuffer仍然為空
mMute(false), mSharedBuffer(sharedBuffer), mName(-1)
{
// mCblk!=NULL? 什么時候創建的呢?只能看基類TrackBase的構造函數了
if(mCblk != NULL) {
mVolume[0] = 1.0f;
mVolume[1] = 1.0f;
mStreamType = streamType;
mCblk->frameSize = AudioSystem::isLinearPCM(format) ?
channelCount * sizeof(int16_t): sizeof(int8_t);
}
}
~~~
對于這種重重繼承,我們只能步步深入分析,一定要找到共享內存創建的地方,繼續看代碼:
**AudioFlinger.cpp**
~~~
AudioFlinger::ThreadBase::TrackBase::TrackBase(
const wp<ThreadBase>& thread,const sp<Client>&client,
uint32_t sampleRate,int format,int channelCount,int frameCount,
uint32_t flags,const sp<IMemory>& sharedBuffer)
: RefBase(), mThread(thread),mClient(client),mCblk(0),
mFrameCount(0),mState(IDLE),mClientTid(-1),mFormat(format),
mFlags(flags & ~SYSTEM_FLAGS_MASK)
{
size_tsize = sizeof(audio_track_cblk_t);//得到CB對象大小
//計算數據緩沖大小
size_tbufferSize = frameCount*channelCount*sizeof(int16_t);
if(sharedBuffer == 0) {
//還記得圖7-4嗎?共享內存最前面一部分是audio_track_cblk_t,后面才是數據空間
size+= bufferSize;
}
//根據size創建一塊共享內存。
mCblkMemory = client->heap()->allocate(size);
/*
pointer()返回共享內存的首地址, 并強制轉換void*類型為audio_track_cblk_t*類型。
其實把它強制轉換成任何類型都可以,但是這塊內存中會有CB對象嗎?
*/
mCblk= static_cast<audio_track_cblk_t *>(mCblkMemory->pointer());
//①下面這句代碼看起來很獨特。什么意思???
new(mCblk)audio_track_cblk_t();
mCblk->frameCount = frameCount;
mCblk->sampleRate = sampleRate;
mCblk->channels = (uint8_t)channelCount;
if (sharedBuffer == 0) {
//清空數據區
mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t);
memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t));
// flowControlFlag初始值為1
mCblk->flowControlFlag = 1;
}
......
}
~~~
這里需要重點講解下面這句話的意思。
~~~
new(mCblk) audio_track_cblk_t();
~~~
注意它的用法,new后面的括號里是內存,緊接其后的是一個類的構造函數。
* * * * *
**重點說明**:這個語句就是C++語言中的placement new。其含義是在括號里指定的內存中創建一個對象。我們知道,普通的new只能在堆上創建對象,堆的地址由系統分配。這里采用placementnew將使得audio_track_cblk_t創建在共享內存上,它就自然而然地能被多個進程看見并使用了。關于placementnew較詳細的知識,還請讀者自己搜索一下。
* * * * *
通過上面的分析,可以知道:
- Track創建了共享內存。
* CB對象通過placement new方法創建于這塊共享內存中。
AF的createTrack函數返回的是一個IAudioTrack類型的對象,可現在碰到的Track對象是IAudioTrack類型嗎?來看代碼:
**AudioFlinger.cpp**
~~~
sp<IAudioTrack> AudioFlinger::createTrack(......)
{
sp<TrackHandle>trackHandle;
......
track= thread->createTrack_l(client, streamType, sampleRate,
format,channelCount,frameCount, sharedBuffer, &lStatus);
trackHandle= new TrackHandle(track);
return trackHandle;//① 這個trackHandle對象竟然沒有在AF中保存!
}
~~~
原來,createTrack返回的是TrackHandle對象,它以Track為參數構造。這二者之間又是什么關系呢?
Android在這里使用了Proxy模式,即TrackHandle是Track的代理,TrackHandle代理的內容是什么呢?分析TrackHandle的定義可以知道:
- Track沒有基于Binder通信,它不能接收來自遠端進程的請求。
- TrackHandle能基于Binder通信,它可以接收來自遠端進程的請求,并且能調用Track對應的函數。這就是Proxy模式的意思。
* * * * *
**討論**:Android為什么不直接讓Track從IBinder派生,直接支持Binder通信呢?關于這個問題,在看到后面的Track家族圖譜后,我們或許就明白了。
* * * * *
另外,注意代碼中的注釋①:
- **trackHandle被new出來后直接返回,而AF中并沒有保存它,這豈不是成了令人聞之色變的野指針?**
* * * * *
拓展思考:關于這個問題的答案,請讀者自己思考并回答。提示,可從Binder和RefBase入手。
* * * * *
分析完createTrack后,估計有些人會暈頭轉向的。確實,這個createTrack比較復雜。僅對象類型就層出不窮。到底它有多少種對象,它們之間又有怎樣的關系呢?下面就來解決這幾個問題。
2. 到底有多少種對象?
不妨把AudioFlinger中出現的對象總結一下,以了解它們的作用和相互之間的關系。
(1) AudioFlinger對象
作為Audio系統的核心引擎,首先要介紹AudioFlinger。它的繼承關系很簡單:
~~~
class AudioFlinger : public BnAudioFlinger,public IBinder::DeathRecipient
~~~
AudioFlinger的主要工作由其定義的許多內部類來完成,我們用圖7-7來表示。圖中大括號所指向的類為外部類,大括號所包含的為該外部類所定義的內部類。例如,DuplicatingThread、RecordThread和DirectOutputThread都包括在一個大括號中,這個大括號指向AudioFlinger,所以它們三個都是AudioFlinger的內部類,而AudioFlinger則是它們三個的外部類:
:-: 
圖7-7 AF中的所有類
看,AF夠復雜吧?要不是使用了VisualStudio的代碼段折疊功能,我畫這個圖,也會破費周折的。
(2) Client對象
Client是AudioFlinger對客戶端的封裝,凡是使用了AudioTrack和AudioRecord的進程,都被會當做是AF的Client,并且Client用它的進程pid作為標識。代碼如下所示:
~~~
class Client : public RefBase {
public:
Client(const sp<AudioFlinger>& audioFlinger, pid_t pid);
virtual ~Client();
const sp<MemoryDealer>& heap() const;
pid_t pid() const {return mPid; }
sp<AudioFlinger> audioFlinger() { return mAudioFlinger; }
private:
Client(constClient&);
Client&operator = (const Client&);
sp<AudioFlinger> mAudioFlinger;
sp<MemoryDealer> mMemoryDealer;//內存分配器
pid_t mPid;
};
~~~
Client對象比較簡單,因此就不做過多的分析了。
>[warning] **注意**:一個Client進程可以創建多個AudioTrack,這些AudioTrack都屬于一個Client。
(3) 工作線程介紹
AudioFlinger中有幾種不同類型的工作線程,它們之間的關系如圖7-8所示:
:-: 
圖7-8 AF中的工作線程家譜
下面來解釋圖7-8中各種類型工作線程的作用:
- PlaybackThread:回放線程,用于音頻輸出。它有一個成員變量mOutput,為AudioStreamOutput*類型,這表明PlaybackThread直接和Audio音頻輸出設備建立了聯系。
- RecordThread:錄音線程,用于音頻輸入,它的關系比較單純。它有一個成員變量mInput為AudioStreamInput*類型,這表明RecordThread直接和Audio音頻輸入設備建立了聯系。
從PlaybackThread的派生關系上可看出,手機上的音頻回放應該比較復雜,否則也不會派生出三個子類了。其中:
- MixerThread:混音線程,它將來自多個源的音頻數據混音后再輸出。
- DirectOutputThread:直接輸出線程,它會選擇一路音頻流后將數據直接輸出,由于沒有混音的操作,這樣可以減少很多延時。
- DuplicatingThread:多路輸出線程,它從MixerThread派生,意味著它也能夠混音。它最終會把混音后的數據寫到多個輸出中,也就是一份數據會有多個接收者。這就是Duplicate的含義。目前在藍牙A2DP設備輸出中使用。
另外從圖7-8中還可以看出:
- PlaybackThread維護兩個Track數組,一個是mActiveTracks,表示當前活躍的Track,一個是mTracks,表示這個線程創建的所有Track。
- DuplicatingThread還維護了一個mOutputTracks,表示多路輸出的目的端。后面分析DuplicatingThread時再對此進行講解。
* * * * *
**說明**:大部分常見音頻輸出使用的是MixerThread,后文會對此進行詳細分析。另外,在拓展內容中,也將深入分析DuplicatingThread的實現。
* * * * *
(4) PlaybackThread和AudioStreamOutput
從圖7-8中,可以發現一個PlaybackThread有一個AudioStreamOutput類型的對象,這個對象提供了音頻數據輸出功能。可以用圖7-9來表示音頻數據的流動軌跡。該圖以PlaybackThread最常用的子類MixerThread作為代表。
:-: 
圖7-9 音頻數據的流動軌跡
根據圖7-9,就能明白MixerThread的大致工作流程:
- 接收來自AT的數據。
- 對這些數據進行混音。
- 把混音的結果寫到AudioStreamOut,這樣就完成了音頻數據的輸出。
(5) Track對象
前面所說的工作線程,其工作就是圍繞Track展開的,圖7-10展示了Track的家族:
:-: 
圖7-10 Track家族
* * * * *
**注意**:這里把RecordTrack也統稱為Track。
* * * * *
從圖7-10中可看出,TrackHandle和RecordHandle是基于Binder通信的,它作為Proxy,用于接收請求并派發給對應的Track和RecordTrack。
* * * * *
**說明**:從圖7-10也能看出,之所以不讓Track繼承Binder框架,是因為Track本身的繼承關系和所承擔的工作已經很復雜了,如再讓它摻合Binder,只會亂上添亂。
* * * * *
Track類作為工作線程的內部類來實現,其中:
- TrackBase定義于ThreadBase中。
- Track定義于PlaybackThread中,RecordTrack定義于RecordThread中。
- OutputTrack定義于DuplicatingThread中。
根據前面的介紹可知,音頻輸出數據最后由Playback線程來處理,用例所對應的Playback線程,實際上是一個MixerThread,那么它是如何工作的呢?一起來分析。
3. MixerThread分析
MixerThread是Audio系統中負擔最重的一個工作線程。先來了解一下它的來歷。
(1) MixerThread的來歷
前面,在checkplaybackThread_l中,有一個地方一直沒來得及解釋。回顧一下它的代碼:
**AudioFlinger.cpp**
~~~
AudioFlinger::PlaybackThread *
AudioFlinger::checkPlaybackThread_l(intoutput) const
{
PlaybackThread*thread = NULL;
//根據output的值找到對應的thread
if(mPlaybackThreads.indexOfKey(output) >= 0) {
thread = (PlaybackThread *)mPlaybackThreads.valueFor(output).get();
}
returnthread;
}
~~~
上面這個函數的意思很明確:就是根據output值找到對應的回放線程。
但在前面的流程分析中,并沒有見到創建線程的地方,那這個線程又是如何得來的?它又是何時、怎樣創建的呢?
答案在AudioPolicyService中。提前看看AudioPolicyService,分析一下,它為什么和這個線程有關系。
AudioPolicyService和AudioFlinger一樣,都駐留在MediaServer中,直接看它的構造函數:
**AudioPolicyService.cpp**
~~~
AudioPolicyService::AudioPolicyService()
:BnAudioPolicyService() , mpPolicyManager(NULL)
{
charvalue[PROPERTY_VALUE_MAX];
// Tone音播放線程
mTonePlaybackThread = new AudioCommandThread(String8(""));
// 命令處理線程
mAudioCommandThread = newAudioCommandThread(String8("ApmCommandThread"));
#if (defined GENERIC_AUDIO) || (defined AUDIO_POLICY_TEST)
//這里屬于Generic的情況,所以構造AudioPolicyManagerBase,注意構造函數的參數
mpPolicyManager = new AudioPolicyManagerBase(this);
#else
......
//創建和硬件廠商相關的AudioPolicyManager
#endif
......
}
~~~
看AudioPolicyManagerBase的構造函數,注意傳給它的參數是this,即把AudioPolicyService對象傳進去了。
**AudioPolicyManagerBase.cpp**
~~~
AudioPolicyManagerBase::AudioPolicyManagerBase(
AudioPolicyClientInterface*clientInterface)
:mPhoneState(AudioSystem::MODE_NORMAL), mRingerMode(0),
mMusicStopTime(0),mLimitRingtoneVolume(false)
{
mpClientInterface = clientInterface;
// 先把不相關的內容去掉
......
/*
返回來調用mpClientInterface的openOutput,實際就是AudioPolicyService。
注意openOutput函數是在AP的創建過程中調用的
*/
mHardwareOutput =mpClientInterface->openOutput(&outputDesc->mDevice,
&outputDesc->mSamplingRate,
&outputDesc->mFormat,
&outputDesc->mChannels,
&outputDesc->mLatency,
outputDesc->mFlags);
......
}
~~~
真是山不轉水轉!咱們還得回到AudioPolicyService中去看看:
**AudioPolicyService.cpp**
~~~
audio_io_handle_tAudioPolicyService::openOutput(uint32_t *pDevices,
uint32_t*pSamplingRate,
uint32_t*pFormat,
uint32_t*pChannels,
uint32_t*pLatencyMs,
AudioSystem::output_flags flags)
{
sp<IAudioFlinger>af = AudioSystem::get_audio_flinger();
//下面會調用AudioFlinger的openOutput,這個時候AF已經啟動了
returnaf->openOutput(pDevices, pSamplingRate, (uint32_t *)pFormat,
pChannels, pLatencyMs,flags);
}
~~~
真是曲折啊,又得到AF去看看:
**AudioFlinger.cpp**
~~~
int AudioFlinger::openOutput(
uint32_t *pDevices,uint32_t*pSamplingRate,uint32_t *pFormat,
uint32_t*pChannels,uint32_t *pLatencyMs,uint32_t flags)
{
......
Mutex::Autolock _l(mLock);
//創建Audio HAL的音頻輸出對象,和音頻輸出扯上了關系
AudioStreamOut *output = mAudioHardware->openOutputStream(*pDevices,
(int *)&format,
&channels,
&samplingRate,
&status);
mHardwareStatus = AUDIO_HW_IDLE;
if(output != 0) {
if((flags & AudioSystem::OUTPUT_FLAG_DIRECT) ||
(format != AudioSystem::PCM_16_BIT) ||
(channels != AudioSystem::CHANNEL_OUT_STEREO)) {
//如果標志為OUTPUT_FLAG_DIRECT,則創建DirectOutputThread
thread = new DirectOutputThread(this, output, ++mNextThreadId);
} else {
//一般創建的都是MixerThread,注意代表AudioStreamOut對象的output也傳進去了
thread= new MixerThread(this, output, ++mNextThreadId);
}
//把新創建的線程加入線程組mPlaybackThreads中保存, mNextThreadId是它的索引號
mPlaybackThreads.add(mNextThreadId, thread);
......
return mNextThreadId;//返回該線程的索引號
}
return0;
}
~~~
明白了嗎?是否感覺有點繞?可用一個簡單的示意圖來觀察三者的交互流程,如圖7-11所示:
:-: 
圖7-11 MixerThread的曲折來歷示意圖
圖7-11表明:
- AF中的工作線程的創建,受到了AudioPolicyService的控制。從AudioPolicyService的角度出發,這也是應該的,因為APS控制著整個音頻系統,而AF只是管理音頻的輸入和輸出。
- 另外,注意這個線程是在AP的創建過程中產生的。也就是說,AP一旦創建完Audio系統,就已經準備好工作了。
關于AF和AP的恩恩怨怨,在后面APS的分析過程中再去探討。目前,讀者只需了解系統中第一個MixerThread的來歷即可。下面來分析這個來之不易的MixerThread。
(2) MixerThread的構造和線程啟動
**AudioFlinger.cpp**
~~~
AudioFlinger::MixerThread::MixerThread(
constsp<AudioFlinger>& audioFlinger,
AudioStreamOut*output, // AudioStreamOut為音頻輸出設備的HAL抽象
intid)
: PlaybackThread(audioFlinger, output, id),mAudioMixer(0)
{
mType = PlaybackThread::MIXER;
//混音器對象,這個對象比較復雜,它完成多路音頻數據的混合工作
mAudioMixer = new AudioMixer(mFrameCount, mSampleRate);
}
~~~
再來看MixerThread的基類PlaybackThread的構造函數:
**AudioFlinger.cpp**
~~~
AudioFlinger::PlaybackThread::PlaybackThread(constsp<AudioFlinger>&
audioFlinger, AudioStreamOut* output, int id)
: ThreadBase(audioFlinger, id),
mMixBuffer(0),mSuspended(0), mBytesWritten(0),
mOutput(output), mLastWriteTime(0),mNumWrites(0),
mNumDelayedWrites(0), mInWrite(false)
{
//獲取音頻輸出HAL對象的一些信息,包括硬件中音頻緩沖區的大小(以幀為單位)
readOutputParameters();
mMasterVolume= mAudioFlinger->masterVolume();
mMasterMute= mAudioFlinger->masterMute();
//設置不同類型音頻流的音量及靜音情況
for(int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++)
{
mStreamTypes[stream].volume=
mAudioFlinger->streamVolumeInternal(stream);
mStreamTypes[stream].mute= mAudioFlinger->streamMute(stream);
}
//發送一個通知消息給監聽者,這部分內容較簡單,讀者可自行研究
sendConfigEvent(AudioSystem::OUTPUT_OPENED);
}
~~~
此時,線程對象已經創建完畢。根據對Thread的分析,應該調用它的run函數才能真正創建新線程。在首次創建sp時調用了run,這里利用了RefBase的onFirstRef函數。根據MixerThread的派生關系,該函數最終由父類PlaybackThread的onFirstRef實現:
**AudioFlinger.cpp**
~~~
void AudioFlinger::PlaybackThread::onFirstRef()
{
constsize_t SIZE = 256;
charbuffer[SIZE];
snprintf(buffer, SIZE, "Playback Thread %p", this);
//下面的run就真正創建了線程并開始執行threadLoop
run(buffer, ANDROID_PRIORITY_URGENT_AUDIO);
}
~~~
好,線程已經run起來了。繼續按流程分析,下一個輪到的調用函數是start。
4. start的分析
AT調用的是IAudioTrack的start函數,由于TrackHandle的代理作用,這個函數的實際處理會由Track對象來完成。
**AudioFlinger.cpp**
~~~
status_tAudioFlinger::PlaybackThread::Track::start()
{
status_t status = NO_ERROR;
sp<ThreadBase>thread = mThread.promote();
//該Thread是用例中的MixerThread
if(thread != 0) {
Mutex::Autolock _l(thread->mLock);
int state = mState;
if (mState == PAUSED) {
mState = TrackBase::RESUMING;
} else {
mState = TrackBase::ACTIVE;//設置Track的狀態
}
PlaybackThread *playbackThread =(PlaybackThread *)thread.get();
//addTrack_l把這個track加入到mActiveTracks數組中
playbackThread->addTrack_l(this);
returnstatus;
}
~~~
看看這個addTrack_l函數,代碼如下所示:
**AudioFlinger.cpp**
~~~
status_tAudioFlinger::PlaybackThread::addTrack_l(const sp<Track>& track)
{
status_t status = ALREADY_EXISTS;
//①mRetryCount:設置重試次數,kMaxTrackStartupRetries值為50
track->mRetryCount = kMaxTrackStartupRetries;
if(mActiveTracks.indexOf(track) < 0) {
//②mFillingUpStatus:緩沖狀態
track->mFillingUpStatus= Track::FS_FILLING;
//原來是把調用start的這個track加入到活躍的Track數組中了
mActiveTracks.add(track);
status = NO_ERROR;
}
//廣播一個事件,一定會觸發MixerThread線程,通知它有活躍數組加入,需要開工干活
mWaitWorkCV.broadcast();
return status;
}
~~~
start函數把這個Track加入到活躍數組后,將觸發一個同步事件,這個事件會讓工作線程動起來。雖然這個函數很簡單,但有兩個關鍵點必須指出,這兩個關鍵點其實指出了兩個問題的處理辦法:
- mRetryCount表示重試次數,它針對的是這樣一個問題:如果一個Track調用了start卻沒有write數據,該怎么辦?如果MixerThread嘗試了mRetryCount次后還沒有可讀數據,工作線程就會把該Track從激活隊列中去掉了。
- mFillingUpStatus能解決這樣的問題:假設分配了1MB的數據緩沖,那么至少需要寫多少數據的工作線程才會讓Track覺得AT是真的需要它工作呢?難道AT寫一個字節就需要工作線程興師動眾嗎?其實,這個狀態最初為Track::FS_FILLING,表示正在填充數據緩沖。在這種狀態下,除非AT設置了強制讀數據標志(CB對象中的forceReady變量),否則工作線程是不會讀取該Track的數據的。該狀態還有其他的值,讀者可以自行研究。
* * * * *
**說明**:我們在介紹大流程的同時也把一些細節問題指出來,希望這些細節問題能激發讀者深入研究的欲望。
* * * * *
Track加入了工作線程的活躍數組后,又觸發了一個同步事件,MixerThread是否真的動起來了呢?一起來看:
(1) MixerThread動起來
Thread類的線程工作都是在threadLoop中完成的,那么MixerThread的線程又會做什么呢?
**AudioFlinger.cpp**
~~~
bool AudioFlinger::MixerThread::threadLoop()
{
int16_t* curBuf = mMixBuffer;
Vector< sp<Track> > tracksToRemove;
uint32_t mixerStatus = MIXER_IDLE;
nsecs_tstandbyTime = systemTime();
......
uint32_t sleepTime = idleSleepTime;
while(!exitPending())
{
//① 處理一些請求和通知消息,如之前在構造函數中發出的OUTPUT_OPEN消息等
processConfigEvents();
mixerStatus = MIXER_IDLE;
{// scope for mLock
Mutex::Autolock _l(mLock);
//檢查配置參數,如有需要則重新設置內部參數值
if (checkForNewParameters_l()) {
mixBufferSize = mFrameCount * mFrameSize;
maxPeriod = seconds(mFrameCount) / mSampleRate * 3;
......
}
//獲得當前的已激活track數組
const SortedVector< wp<Track> >& activeTracks =mActiveTracks;
......
/*
②prepareTracks_l將檢查mActiveTracks數組,判斷是否有AT的數據需要處理。
例如有些AudioTrack雖然調用了start,但是沒有及時write數據,這時就無須
進行混音工作。我們待會再分析prepareTracks_l函數
*/
mixerStatus = prepareTracks_l(activeTracks, &tracksToRemove);
}
//MIXER_TRACKS_READY表示AT已經把數據準備好了
if(LIKELY(mixerStatus == MIXER_TRACKS_READY)) {
//③ 由混音對象進行混音工作,混音的結果放在curBuf中
mAudioMixer->process(curBuf);
sleepTime = 0;//等待時間設置為零,表示需要馬上輸出到Audio HAL
standbyTime = systemTime() + kStandbyTimeInNsecs;
}
.......
if(sleepTime == 0) {
......
//④ 往Audio HAL的OutputStream中write混音后的數據,這是音頻數據的最終歸宿
int bytesWritten = (int)mOutput->write(curBuf, mixBufferSize);
if (bytesWritten < 0) mBytesWritten -= mixBufferSize;
......
mStandby = false;
}else {
usleep(sleepTime);
}
tracksToRemove.clear();
}
if(!mStandby) {
mOutput->standby();
}
returnfalse;
}
~~~
從上面的分析可以看出,MixerThread的線程函數大致工作流程是:
- 如果有通知信息或配置請求,則先完成這些工作。比如向監聽者通知AF的一些信息,或者根據配置請求進行音量控制,聲音設備切換等。
- 調用prepareTracks _l函數,檢查活躍Tracks是否有數據準備好。
- 調用混音器對象mAudioMixer的process,并且傳入一個存儲結果數據的緩沖,混音后的結果就存儲在這個緩沖中。
- 調用代表音頻輸出設備的AudioOutputStream對象的write,把結果數據寫入設備。
其中,配置請求處理的工作將在AudioPolicyService的分析中,以一個耳機插入處理實例進行講解。這里主要分析代碼中②③兩個步驟。
(2) prepareTracks_l和process分析
prepareTracks_l函數檢查激活Track數組,看看其中是否有數據等待使用,代碼如下所示:
**AudioFlinger.cpp**
~~~
uint32_tAudioFlinger::MixerThread::prepareTracks_l(
constSortedVector<wp<Track>>& activeTracks,
Vector<sp<Track>>*tracksToRemove)
{
uint32_t mixerStatus = MIXER_IDLE;
//激活Track的個數
size_tcount = activeTracks.size();
floatmasterVolume = mMasterVolume;
bool masterMute = mMasterMute;
//依次查詢這些Track的情況
for(size_t i=0 ; i<count ; i++) {
sp<Track> t = activeTracks[i].promote();
if(t == 0) continue;
Track* const track = t.get();
//怎么查?通過audio_track_cblk_t對象
audio_track_cblk_t* cblk = track->cblk();
/*
一個混音器可支持32個Track,它內部有一個32元素的數組,name函數返回的就是Track在
這個數組中的索引。混音器每次通過setActiveTrack設置一個活躍Track,
后續所有操作都會針對當前設置的這個活躍Track
*/
mAudioMixer->setActiveTrack(track->name());
//下面這個判斷語句決定了什么情況下Track數據可用
if (cblk->framesReady() &&(track->isReady() || track->isStopped())
&& !track->isPaused()&& !track->isTerminated())
{
......
/*
設置活躍Track的數據提供者為Track本身,因為Track從AudioBufferProvider
派生。混音器工作時,需從Track得到待混音的數據,也就是AT寫入的數據由混音
器取出并消費
*/
mAudioMixer->setBufferProvider(track);
//設置對應Track的混音標志
mAudioMixer->enable(AudioMixer::MIXING);
......
//設置該Track的音量等信息,這在以后的混音操作中會使用
mAudioMixer->setParameter(param, AudioMixer::VOLUME0, left);
mAudioMixer->setParameter(param,AudioMixer::VOLUME1, right);
mAudioMixer->setParameter(
AudioMixer::TRACK,
AudioMixer::FORMAT, track->format());
......
mixerStatus = MIXER_TRACKS_READY;
}else {//如果不滿足上面的條件,則走else分支
if (track->isStopped()) {
track->reset();//reset會清零讀寫位置,表示沒有可讀數據
}
//如果處于這三種狀態之一,則加入移除隊列
if (track->isTerminated() || track->isStopped()
|| track->isPaused()) {
tracksToRemove->add(track);
mAudioMixer->disable(AudioMixer::MIXING);
} else {
//不處于上面三種狀態時,表示暫時沒有可讀數據,則重試mRetryCount次
if (--(track->mRetryCount) <= 0) {
tracksToRemove->add(track);
} else if (mixerStatus != MIXER_TRACKS_READY) {
mixerStatus =MIXER_TRACKS_ENABLED;
}
//禁止這個Track的混音
mAudioMixer->disable(AudioMixer::MIXING);
......
}
}
}
//對那些被移除的Track做最后的處理
......
returnmixerStatus;
}
~~~
當所有Track準備就緒后,最重要的工作就是混音。混音對象的process就派上了用場。來看這個process函數,代碼如下所示:
**AudioMixer.cpp**
~~~
void AudioMixer::process(void* output)
{
mState.hook(&mState, output);//hook?這是一個函數指針
}
~~~
hook是函數指針,它根據Track的個數和它的音頻數據格式(采樣率等)等情況,使用不同的處理函數。為進一步了解混音器是如何工作的,需要先分析AudioMixer對象。
(3) AudioMixer對象的分析
AudioMixer實現AudioMixer.cpp中,先看構造函數:
**AudioMixer.cpp**
~~~
AudioMixer::AudioMixer(size_t frameCount,uint32_t sampleRate)
: mActiveTrack(0), mTrackNames(0),mSampleRate(sampleRate)
{
mState.enabledTracks= 0;
mState.needsChanged = 0;
mState.frameCount = frameCount;//這個值等于音頻輸出對象的緩沖大小
mState.outputTemp = 0;
mState.resampleTemp= 0;
//hook初始化的時候為process__nop,這個函數什么都不會做
mState.hook = process__nop;
track_t*t = mState.tracks;//track_t是和Track相對應的一個結構
//最大支持32路混音,也很不錯了
for(int i=0 ; i<32 ; i++) {
......
t->channelCount = 2;
t->enabled = 0;
t->format = 16;
t->buffer.raw = 0;
t->bufferProvider = 0; // bufferProvider為這一路Track的數據提供者
t->hook = 0;//每一個Track也有一個hook函數
......
}
int mActiveTrack;
uint32_t mTrackNames;
constuint32_t mSampleRate;
state_t mState
}
~~~
其中,mState是在AudioMixer類中定義的一個數據結構。
~~~
struct state_t {
uint32_t enabledTracks;
uint32_t needsChanged;
size_t frameCount;
mix_t hook;
int32_t *outputTemp;
int32_t *resampleTemp;
int32_t reserved[2];
/*
aligned表示32字節對齊,由于source insight不認識這個標志,導致
state_t不能被解析。在看代碼時,可以注釋掉后面的attribute,這樣source insight
就可以識別state_t結構了
*/
track_t tracks[32]; __attribute__((aligned(32)));
};
~~~
AudioMixer為hook準備了多個實現函數,來看:
- process__validate:根據Track的格式、數量等信息選擇其他的處理函數。
- process__nop:什么都不做。
- process__genericNoResampling:普通無需重采樣。
- process__genericResampling:普通需重采樣。
- process__OneTrack16BitsStereoNoResampling:一路音頻流,雙聲道,PCM16格式,無需重采樣。
- process__TwoTracks16BitsStereoNoResampling:兩路音頻流,雙聲道,PCM16格式,無需重采樣。
hook最初的值為process__nop,這一定不會是混音中最終使用的處理函數,難道有動態賦值的地方?是的。一起來看:
(4) 殺雞不用宰牛刀
在AF的prepare_l中,會為每一個準備好的Track使能混音標志:
~~~
mAudioMixer->setBufferProvider(track);
mAudioMixer->enable(AudioMixer::MIXING);//使能混音
~~~
請看enable的實現:
**AudioMixer.cpp**
~~~
status_t AudioMixer::enable(int name)
{
switch(name) {
case MIXING: {
if (mState.tracks[ mActiveTrack ].enabled != 1) {
mState.tracks[ mActiveTrack ].enabled = 1;
//注意這個invalidateState調用
invalidateState(1<<mActiveTrack);
}
}break;
default:
return NAME_NOT_FOUND;
}
returnNO_ERROR;
}
~~~
**AudioMixer.cpp**
~~~
void AudioMixer::invalidateState(uint32_t mask)
{
if(mask) {
mState.needsChanged |= mask;
mState.hook = process__validate;//將hook設置為process_validate
}
}
~~~
process_validate會根據當前Track的情況選擇不同的處理函數,所以不會出現殺雞卻用災牛刀的情況。
**AudioMixer.cpp**
~~~
void AudioMixer::process__validate(state_t*state, void* output)
{
uint32_t changed = state->needsChanged;
state->needsChanged = 0;
uint32_t enabled = 0;
uint32_t disabled = 0;
......
if(countActiveTracks) {
if(resampling) {
......
//如果需要重采樣,則選擇process__genericResampling
state->hook = process__genericResampling;
}else {
......
state->hook = process__genericNoResampling;
if (all16BitsStereoNoResample && !volumeRamp) {
if (countActiveTracks == 1) {
//如果只有一個Track,則使用process__OneTrack16BitsStereoNoResampling
state->hook =process__OneTrack16BitsStereoNoResampling;
}
}
}
}
state->hook(state, output);
......
}
~~~
假設用例運行時,系統只有這么一個Track,那么hook函數使用的就是process__OneTrack16BitsStereoNoResampling處理。process_XXX函數會涉及很多數字音頻處理的專業知識,先不用去討論它。數據緩沖的消費工作是在這個函數中完成的,因此應重點關注它是如何通過CB對象使用數據緩沖的。
* * * * *
**說明**:在這個數據消費和之前破解AT的過程中所講的數據生產是對應的,先來提煉AT和AF在生產和消費這兩個環節上與CB交互的流程。
* * * * *
(5) 怎么消費數據
在AudioTrack中,曾講到數據的生產流程:
- ObtainBuffer,得到一塊數據緩沖。
- memcpy數據到該緩沖。
- releaseBuffer,釋放這個緩沖。
那么做為消費者,AudioFlinger是怎么獲得這些數據的呢?
**AudioMixer.cpp**
~~~
voidAudioMixer::process__OneTrack16BitsStereoNoResampling(
state_t*state, void* output)
{
//找到被激活的Track,此時只能有一個Track,否則就不會選擇這個process函數了
constint i = 31 - __builtin_clz(state->enabledTracks);
consttrack_t& t = state->tracks[i];
AudioBufferProvider::Buffer& b(t.buffer);
......
while(numFrames) {
b.frameCount = numFrames;
//BufferProvider就是Track對象,調用它的getNextBuffer獲得可讀數據緩沖
t.bufferProvider->getNextBuffer(&b);
int16_t const *in = b.i16;
......
size_t outFrames = b.frameCount;
do {//數據處理,也即是混音
uint32_t rl = *reinterpret_cast<uint32_t const *>(in);
in += 2;
int32_t l = mulRL(1, rl, vrl) >> 12;
int32_t r = mulRL(0, rl, vrl) >> 12;
//把數據復制給out緩沖
*out++ = (r<<16) | (l & 0xFFFF);
} while (--outFrames);
}
numFrames -= b.frameCount;
//調用Track的releaseBuffer釋放緩沖
t.bufferProvider->releaseBuffer(&b);
}
}
~~~
bufferProvider就是Track對象,總結一下它使用數據緩沖的調用流程:
- 調用Track的getNextBuffer,得到可讀數據緩沖。
- 調用Track的releaseBuffer,釋放數據緩沖。
現在來分析上面這兩個函數:getNextBuffer和releaseBuffer。
(6) getNextBuffer和releaseBuffer的分析
先看getNextBuffer。它從數據緩沖中得到一塊可讀空間:
**AudioFlinger.cpp**
~~~
status_tAudioFlinger::PlaybackThread::Track::getNextBuffer(
AudioBufferProvider::Buffer*buffer)
{
audio_track_cblk_t*cblk = this->cblk();//通過CB對象完成
uint32_t framesReady;
//frameCount為AudioOutput音頻輸出對象的緩沖區大小
uint32_t framesReq = buffer->frameCount;
......
//根據CB的讀寫指針計算有多少幀數據可讀
framesReady = cblk->framesReady();
if (LIKELY(framesReady)){
uint32_t s = cblk->server; //當前讀位置
//可讀的最大位置,為當前讀位置加上frameCount
uint32_tbufferEnd = cblk->serverBase + cblk->frameCount;
//AT可以通過setLooping設置播放的起點和終點,如果有終點的話,需要以loopEnd
//作為數據緩沖的末尾
bufferEnd = (cblk->loopEnd < bufferEnd) ? cblk->loopEnd :bufferEnd;
if(framesReq > framesReady) {
//如果要求的讀取幀數大于可讀幀數,則只能選擇實際可讀的幀數
framesReq = framesReady;
}
//如果可讀幀數的最后位置超過了AT設置的末端點,則需要重新計算可讀幀數
if(s + framesReq > bufferEnd) {
framesReq = bufferEnd - s;
}
//根據讀起始位置得到數據緩沖的起始地址,framesReq參數用來做內部檢查,防止出錯
buffer->raw = getBuffer(s, framesReq);
if (buffer->raw == 0) goto getNextBuffer_exit;
buffer->frameCount = framesReq;
return NO_ERROR;
}
getNextBuffer_exit:
buffer->raw = 0;
buffer->frameCount = 0;
return NOT_ENOUGH_DATA;
}
~~~
getNextBuffer非常簡單,不過就是根據CB記錄的讀寫位置等計算可讀的緩沖位置。下面來看releaseBuffer的操作。
**AudioFlinger.cpp**
~~~
void AudioFlinger::ThreadBase::TrackBase::releaseBuffer(
AudioBufferProvider::Buffer*buffer)
{
buffer->raw = 0;
mFrameCount = buffer->frameCount;//frameCount為getNextBuffer中分配的可讀幀數
step();//調用step函數
buffer->frameCount = 0;
}
~~~
**AudioFlinger.cpp**
~~~
bool AudioFlinger::ThreadBase::TrackBase::step(){
boolresult;
audio_track_cblk_t* cblk = this->cblk();
//調用stepServer更新讀位置
result= cblk->stepServer(mFrameCount);
if(!result) {
mFlags |= STEPSERVER_FAILED;
}
returnresult;
}
~~~
getNextBuffer和releaseBuffer這兩個函數相對比較簡單。把它和CB交互的流程總結一下,為后面進行CB對象的分析做鋪墊:
- getNextBuffer通過frameReady得到可讀幀數。
- getBuffer函數將根據可讀幀數等信息得到可讀空間的首地址。
- releaseBuffer通過stepServer更新讀位置。
5. stop的分析
(1) TrackHandle和Track的回收
來自AT的stop請求最終會通過TrackHandle這個Proxy交給Track的stop處理。請直接看Track的stop:
**AudioFlinger.cpp**
~~~
void AudioFlinger::PlaybackThread::Track::stop()
{
sp<ThreadBase> thread = mThread.promote();
if(thread != 0) {
Mutex::Autolock _l(thread->mLock);
int state = mState;//保存舊的狀態
if(mState > STOPPED) {
mState = STOPPED;//設置新狀態為STOPPED
PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
if (playbackThread->mActiveTracks.indexOf(this) < 0) {
reset();//如果該線程的活躍數組中沒有Track,則重置讀寫位置
}
}
//和APS相關,我們不在這里討論,它不直接影響AudioFlinger
if(!isOutputTrack() && (state == ACTIVE || state == RESUMING)) {
thread->mLock.unlock();
AudioSystem::stopOutput(thread->id(),
(AudioSystem::stream_type)mStreamType);
thread->mLock.lock();
}
}
}
~~~
如果Track最初處于活躍數組,那么這個stop函數無非是把mState設置為STOPPED了,但播放該怎么停止呢?請再回頭看prepareTrack_l中的那個判斷:
~~~
if (cblk->framesReady() &&(track->isReady() || track->isStopped())
&& !track->isPaused() &&!track->isTerminated())
~~~
假設AT寫數據快,而AF消耗數據慢,那么上面這個判斷語句在一定時間內是成立的,換言之,如果僅僅調用了stop,還是會聽到聲音,該怎么辦?在一般情況下,AT端stop后會很快被delete,這將導致AF端的TrackHandle也被delete。
說明:在介紹Track和TrackHandle一節中,曾在最后提到了那個野指針問題。相信讀者這時候會知道那個問題的答案了,是嗎?
看TrackHandle的析構函數:
**AudioFlinger.cpp**
~~~
AudioFlinger::TrackHandle::~TrackHandle() {
mTrack->destroy();
}
~~~
**AudioFlinger.cpp**
~~~
voidAudioFlinger::PlaybackThread::Track::destroy()
{
sp<Track> keep(this);
{
sp<ThreadBase> thread = mThread.promote();
if(thread != 0) {
if (!isOutputTrack()) {
//和AudioSystem相關,以后再分析
if (mState == ACTIVE || mState == RESUMING) {
AudioSystem::stopOutput(thread->id(),
(AudioSystem::stream_type)mStreamType);
}
AudioSystem::releaseOutput(thread->id());
}
Mutex::Autolock _l(thread->mLock);
PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
//調用回放線程對象的destroyTrack_l
playbackThread->destroyTrack_l(this);
}
}
}
~~~
**AudioFlinger.cpp**
~~~
voidAudioFlinger::PlaybackThread::destroyTrack_l(const sp<Track>& track)
{
track->mState = TrackBase::TERMINATED;//設置狀態為TERMINATED
if(mActiveTracks.indexOf(track) < 0) {
mTracks.remove(track);//如果不在mActiveTracks數組中,則把它從mTracks中去掉。
//由PlaybackThread的子類實現,一般就是回收一些資源等工作
deleteTrackName_l(track->name());
}
}
~~~
TrackHandle的delete最后會導致它所代理的Track對象也被刪除,那么Client對象什么時候被回收呢?
(2) Client的回收
直接看TrackBase的析構,因為Track的析構會導致它的基類TrackBase析構函數被調用,代碼如下所示:
**AudioFlinger.cpp**
~~~
AudioFlinger::ThreadBase::TrackBase::~TrackBase()
{
if (mCblk) {
//placementnew出來的對象需要顯示調用的析構函數
mCblk->~audio_track_cblk_t();
if(mClient == NULL) {
delete mCblk;//先調用析構,再釋放內存,這是placement new的用法
}
}
mCblkMemory.clear();
if(mClient != NULL) {
Mutex::Autolock _l(mClient->audioFlinger()->mLock);
mClient.clear();//如果mClient的強弱引用計數都為0,則會導致該Client被delete
}
}
~~~
資源回收的工作相對比較簡單,這里就不做過多的討論了,讀者可自行分析研究。
* * * * *
**說明**:其實,要找到TrackHandle是什么時候被delete,會更有難度。
* * * * *
- 前言
- 第1章 閱讀前的準備工作
- 1.1 系統架構
- 1.1.1 Android系統架構
- 1.1.2 本書的架構
- 1.2 搭建開發環境
- 1.2.1 下載源碼
- 1.2.2 編譯源碼
- 1.3 工具介紹
- 1.3.1 Source Insight介紹
- 1.3.2 Busybox的使用
- 1.4 本章小結
- 第2章 深入理解JNI
- 2.1 JNI概述
- 2.2 學習JNI的實例:MediaScanner
- 2.3 Java層的MediaScanner分析
- 2.3.1 加載JNI庫
- 2.3.2 Java的native函數和總結
- 2.4 JNI層MediaScanner的分析
- 2.4.1 注冊JNI函數
- 2.4.2 數據類型轉換
- 2.4.3 JNIEnv介紹
- 2.4.4 通過JNIEnv操作jobject
- 2.4.5 jstring介紹
- 2.4.6 JNI類型簽名介紹
- 2.4.7 垃圾回收
- 2.4.8 JNI中的異常處理
- 2.5 本章小結
- 第3章 深入理解init
- 3.1 概述
- 3.2 init分析
- 3.2.1 解析配置文件
- 3.2.2 解析service
- 3.2.3 init控制service
- 3.2.4 屬性服務
- 3.3 本章小結
- 第4章 深入理解zygote
- 4.1 概述
- 4.2 zygote分析
- 4.2.1 AppRuntime分析
- 4.2.2 Welcome to Java World
- 4.2.3 關于zygote的總結
- 4.3 SystemServer分析
- 4.3.1 SystemServer的誕生
- 4.3.2 SystemServer的重要使命
- 4.3.3 關于 SystemServer的總結
- 4.4 zygote的分裂
- 4.4.1 ActivityManagerService發送請求
- 4.4.2 有求必應之響應請求
- 4.4.3 關于zygote分裂的總結
- 4.5 拓展思考
- 4.5.1 虛擬機heapsize的限制
- 4.5.2 開機速度優化
- 4.5.3 Watchdog分析
- 4.6 本章小結
- 第5章 深入理解常見類
- 5.1 概述
- 5.2 以“三板斧”揭秘RefBase、sp和wp
- 5.2.1 第一板斧--初識影子對象
- 5.2.2 第二板斧--由弱生強
- 5.2.3 第三板斧--破解生死魔咒
- 5.2.4 輕量級的引用計數控制類LightRefBase
- 5.2.5 題外話-三板斧的來歷
- 5.3 Thread類及常用同步類分析
- 5.3.1 一個變量引發的思考
- 5.3.2 常用同步類
- 5.4 Looper和Handler類分析
- 5.4.1 Looper類分析
- 5.4.2 Handler分析
- 5.4.3 Looper和Handler的同步關系
- 5.4.4 HandlerThread介紹
- 5.5 本章小結
- 第6章 深入理解Binder
- 6.1 概述
- 6.2 庖丁解MediaServer
- 6.2.1 MediaServer的入口函數
- 6.2.2 獨一無二的ProcessState
- 6.2.3 時空穿越魔術-defaultServiceManager
- 6.2.4 注冊MediaPlayerService
- 6.2.5 秋風掃落葉-StartThread Pool和join Thread Pool分析
- 6.2.6 你徹底明白了嗎
- 6.3 服務總管ServiceManager
- 6.3.1 ServiceManager的原理
- 6.3.2 服務的注冊
- 6.3.3 ServiceManager存在的意義
- 6.4 MediaPlayerService和它的Client
- 6.4.1 查詢ServiceManager
- 6.4.2 子承父業
- 6.5 拓展思考
- 6.5.1 Binder和線程的關系
- 6.5.2 有人情味的訃告
- 6.5.3 匿名Service
- 6.6 學以致用
- 6.6.1 純Native的Service
- 6.6.2 扶得起的“阿斗”(aidl)
- 6.7 本章小結
- 第7章 深入理解Audio系統
- 7.1 概述
- 7.2 AudioTrack的破解
- 7.2.1 用例介紹
- 7.2.2 AudioTrack(Java空間)分析
- 7.2.3 AudioTrack(Native空間)分析
- 7.2.4 關于AudioTrack的總結
- 7.3 AudioFlinger的破解
- 7.3.1 AudioFlinger的誕生
- 7.3.2 通過流程分析AudioFlinger
- 7.3.3 audio_track_cblk_t分析
- 7.3.4 關于AudioFlinger的總結
- 7.4 AudioPolicyService的破解
- 7.4.1 AudioPolicyService的創建
- 7.4.2 重回AudioTrack
- 7.4.3 聲音路由切換實例分析
- 7.4.4 關于AudioPolicy的總結
- 7.5 拓展思考
- 7.5.1 DuplicatingThread破解
- 7.5.2 題外話
- 7.6 本章小結
- 第8章 深入理解Surface系統
- 8.1 概述
- 8.2 一個Activity的顯示
- 8.2.1 Activity的創建
- 8.2.2 Activity的UI繪制
- 8.2.3 關于Activity的總結
- 8.3 初識Surface
- 8.3.1 和Surface有關的流程總結
- 8.3.2 Surface之乾坤大挪移
- 8.3.3 乾坤大挪移的JNI層分析
- 8.3.4 Surface和畫圖
- 8.3.5 初識Surface小結
- 8.4 深入分析Surface
- 8.4.1 與Surface相關的基礎知識介紹
- 8.4.2 SurfaceComposerClient分析
- 8.4.3 SurfaceControl分析
- 8.4.4 writeToParcel和Surface對象的創建
- 8.4.5 lockCanvas和unlockCanvasAndPost分析
- 8.4.6 GraphicBuffer介紹
- 8.4.7 深入分析Surface的總結
- 8.5 SurfaceFlinger分析
- 8.5.1 SurfaceFlinger的誕生
- 8.5.2 SF工作線程分析
- 8.5.3 Transaction分析
- 8.5.4 關于SurfaceFlinger的總結
- 8.6 拓展思考
- 8.6.1 Surface系統的CB對象分析
- 8.6.2 ViewRoot的你問我答
- 8.6.3 LayerBuffer分析
- 8.7 本章小結
- 第9章 深入理解Vold和Rild
- 9.1 概述
- 9.2 Vold的原理與機制分析
- 9.2.1 Netlink和Uevent介紹
- 9.2.2 初識Vold
- 9.2.3 NetlinkManager模塊分析
- 9.2.4 VolumeManager模塊分析
- 9.2.5 CommandListener模塊分析
- 9.2.6 Vold實例分析
- 9.2.7 關于Vold的總結
- 9.3 Rild的原理與機制分析
- 9.3.1 初識Rild
- 9.3.2 RIL_startEventLoop分析
- 9.3.3 RIL_Init分析
- 9.3.4 RIL_register分析
- 9.3.5 關于Rild main函數的總結
- 9.3.6 Rild實例分析
- 9.3.7 關于Rild的總結
- 9.4 拓展思考
- 9.4.1 嵌入式系統的存儲知識介紹
- 9.4.2 Rild和Phone的改進探討
- 9.5 本章小結
- 第10章 深入理解MediaScanner
- 10.1 概述
- 10.2 android.process.media分析
- 10.2.1 MSR模塊分析
- 10.2.2 MSS模塊分析
- 10.2.3 android.process.media媒體掃描工作的流程總結
- 10.3 MediaScanner分析
- 10.3.1 Java層分析
- 10.3.2 JNI層分析
- 10.3.3 PVMediaScanner分析
- 10.3.4 關于MediaScanner的總結
- 10.4 拓展思考
- 10.4.1 MediaScannerConnection介紹
- 10.4.2 我問你答
- 10.5 本章小結