Android -- Audio Native服務之啟動流程分析(一)._第1頁
Android -- Audio Native服務之啟動流程分析(一)._第2頁
Android -- Audio Native服務之啟動流程分析(一)._第3頁
Android -- Audio Native服務之啟動流程分析(一)._第4頁
Android -- Audio Native服務之啟動流程分析(一)._第5頁
已閱讀5頁,還剩31頁未讀 繼續免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

1、Android - Audio Native服務之啟動流程分析(一)Android中的Audio系統是比較龐大、繁雜的一部分內容, 其中會涉及較多的音頻編解碼、多媒體制式與Android Audio HAL設備管理的知識。隨著Android的發展,其所支持的音頻設備也變得越來豐富,如揚聲器、耳機、聽筒等等;這種變化也為Android管理如此豐富的音頻設備以及如何正確、合理地切換音頻輸出提出了更高的要求。面對如此繁雜的管理要求,我們分析Android Audio服務的歷程想必也不會輕松。接下來,我們會以Audio Native服務的啟動為入口,以其基本實現流程為重點,抓住代碼中的各個關鍵點,循序

2、漸進地學習Android Audio部分的知識,先讓我們對它有一個基本的認識和了解;其他的代碼細節分析,則需要我們在工作、學習中花費更多的時間去揣摩和思考了。Android Audio部分最主要的Native服務有兩個:AudioFlinger和AudioPolicyService。AudioFlinger是Android Audio系統的核心與中樞。從上,它為Android Audio API實現提供具體的功能接口;向下,它與Audio HAL層交互,管理音頻設備。我們知道HAL層是Android對各個物理設備的代碼抽象。HAL層中封裝了操作物理設備的接口,通過調用這些接口,我們就可以操作設

3、備,實現我們自己的功能。又由于AudioFlinger負責管理這些Audio設備,所以我們可以猜測它有一套自己的機制,來區分和管理這些Audio Interface。同時,AudioFlinger直接與HAL交互,它其中也必然實現了音頻數據管理、音頻輸入輸出等功能。我們也要注意,Android中支持多種音頻設備,那么就需要有一位大師來管理音頻數據到底從哪種設備輸入或者輸出;這就牽扯到一種策略制定的問題,它指引音頻數據的流向,即與哪種物理設備交互。既然是制定策略,那這位大師當然就是AudioPolicyService。基于這種分工,我們可以得出:AudioFlinger是一個工作繁重的服務,它是

4、Audio策略的功能執行者,直接負責音頻數據與音頻設備的交互;而策略由AudioPolicyService制定,它負責把控AudioFlinger的工作方向。有了這些概念,我們再去分析AudioFlinger和AudioPolicyService的服務啟動過程。與之前不同的是,較新的Android系統中,Audio相關的服務都被移動了audioserver進程中。系統啟動的時候,會創建該進程,其中就有AudioFlinger和AudioPolicyService的啟動處理:cpp view plain copy 在CODE上查看代碼片派生到我的代碼片int main(int argc _unu

5、sed, char *argv) signal(SIGPIPE, SIG_IGN); bool doLog = (bool) property_get_bool(ro.test_harness, 0); pid_t childPid; / FIXME The advantage of making the process containing media.log service the parent process of / the process that contains the other audio services, is that it allows us to collect m

6、ore / detailed information such as signal numbers, stop and continue, resource usage, etc. / But it is also more complex. Consider replacing this by independent processes, and using / binder on death notification instead. if (doLog & (childPid = fork() != 0) / media.log service /prctl(PR_SET_NAME, (

7、unsigned long) media.log, 0, 0, 0); / unfortunately ps ignores PR_SET_NAME for the main thread, so use this ugly hack strcpy(argv0, media.log); sp proc(ProcessState:self(); MediaLogService:instantiate(); ProcessState:self()-startThreadPool(); IPCThreadState:self()-joinThreadPool(); for (;) siginfo_t

8、 info; int ret = waitid(P_PID, childPid, &info, WEXITED | WSTOPPED | WCONTINUED); if (ret = EINTR) continue; if (ret 0) break; char buffer32; const char *code; switch (info.si_code) case CLD_EXITED: code = CLD_EXITED; break; case CLD_KILLED: code = CLD_KILLED; break; case CLD_DUMPED: code = CLD_DUMP

9、ED; break; case CLD_STOPPED: code = CLD_STOPPED; break; case CLD_TRAPPED: code = CLD_TRAPPED; break; case CLD_CONTINUED: code = CLD_CONTINUED; break; default: snprintf(buffer, sizeof(buffer), unknown (%d), info.si_code); code = buffer; break; struct rusage usage; getrusage(RUSAGE_CHILDREN, &usage);

10、ALOG(LOG_ERROR, media.log, pid %d status %d code %s user %ld.%03lds sys %ld.%03lds, info.si_pid, info.si_status, code, usage.ru_utime.tv_sec, usage.ru_utime.tv_usec / 1000, usage.ru_stime.tv_sec, usage.ru_stime.tv_usec / 1000); sp sm = defaultServiceManager(); sp binder = sm-getService(String16(medi

11、a.log); if (binder != 0) Vector args; binder-dump(-1, args); switch (info.si_code) case CLD_EXITED: case CLD_KILLED: case CLD_DUMPED: ALOG(LOG_INFO, media.log, exiting); _exit(0); / not reached default: break; else / all other services if (doLog) prctl(PR_SET_PDEATHSIG, SIGKILL); / if parent media.l

12、og dies before me, kill me also setpgid(0, 0); / but if I die first, dont kill my parent sp proc(ProcessState:self(); sp sm = defaultServiceManager(); ALOGI(ServiceManager: %p, sm.get(); AudioFlinger:instantiate();/啟動AudioFlinger AudioPolicyService:instantiate();/啟動AudioPolicyService RadioService:in

13、stantiate(); SoundTriggerHwService:instantiate(); ProcessState:self()-startThreadPool(); IPCThreadState:self()-joinThreadPool(); AudioFlinger:instantiate()、AudioPolicyService:instantiate()的調用就是服務的啟動過程,下面我們一一分析。一、AudioFlinger:instantiate()AudioFlinger的繼承關系聲明如下:cpp view plain copy 在CODE上查看代碼片派生到我的代碼片c

14、lass AudioFlinger : public BinderService, public BnAudioFlinger AudioFlinger是一個Binder服務的服務端實現,整個AudioFlinger的Binder服務結構如圖所示:繼承BnAudioFlinger說明它確實是IAudioFlinger的服務端;而BinderService更像是一個模板工具類,它封裝了Binder服務發布、啟動的一些方法:cpp view plain copy 在CODE上查看代碼片派生到我的代碼片template class BinderService public: static statu

15、s_t publish(bool allowIsolated = false) sp sm(defaultServiceManager(); return sm-addService( String16(SERVICE:getServiceName(), new SERVICE(), allowIsolated); static void publishAndJoinThreadPool(bool allowIsolated = false) publish(allowIsolated); joinThreadPool(); static void instantiate() publish(

16、); static status_t shutdown() return NO_ERROR; private: static void joinThreadPool() sp ps(ProcessState:self(); ps-startThreadPool(); ps-giveThreadPoolName(); IPCThreadState:self()-joinThreadPool(); ; BinderService:instantiate()內部會創建AudioFlinger服務實例,并通過ServiceManager將其發布到系統中;其中,AudioFlinger服務注冊的名稱是“

17、media.audio_flinger”。我們看看IAudioFlinger和AudioFlinger的定義。首先是IAudioFlinger:cpp view plain copy 在CODE上查看代碼片派生到我的代碼片class IAudioFlinger : public IInterface public: DECLARE_META_INTERFACE(AudioFlinger); / invariant on exit for all APIs that return an sp: / (return value != 0) = (*status = NO_ERROR) /* cre

18、ate an audio track and registers it with AudioFlinger. * return null if the track cannot be created. */ virtual sp createTrack() = 0;/AudioTrack使用時會涉及到 virtual sp openRecord() = 0; / FIXME Surprisingly, format/latency dont work for input handles /* query the audio hardware state. This state never ch

19、anges, * and therefore can be cached. */ virtual uint32_t sampleRate(audio_io_handle_t ioHandle) const = 0; / reserved; formerly channelCount() virtual audio_format_t format(audio_io_handle_t output) const = 0; virtual size_t frameCount(audio_io_handle_t ioHandle) const = 0; / return estimated laten

20、cy in milliseconds virtual uint32_t latency(audio_io_handle_t output) const = 0; /* set/get the audio hardware state. This will probably be used by * the preference panel, mostly. */ virtual status_t setMasterVolume(float value) = 0; . virtual bool masterMute() const = 0; /* set/get stream type stat

21、e. This will probably be used by * the preference panel, mostly. */ virtual status_t setStreamVolume(audio_stream_type_t stream, float value, audio_io_handle_t output) = 0; . virtual bool streamMute(audio_stream_type_t stream) const = 0; / set audio mode virtual status_t setMode(audio_mode_t mode) =

22、 0; / mic mute/state virtual status_t setMicMute(bool state) = 0; virtual bool getMicMute() const = 0; virtual status_t setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs) = 0; virtual String8 getParameters(audio_io_handle_t ioHandle, const String8& keys) const = 0; virtual statu

23、s_t openOutput() = 0; virtual audio_io_handle_t openDuplicateOutput() = 0; virtual status_t closeOutput(audio_io_handle_t output) = 0; virtual status_t suspendOutput(audio_io_handle_t output) = 0; virtual status_t restoreOutput(audio_io_handle_t output) = 0; virtual status_t openInput() = 0; virtual

24、 status_t closeInput(audio_io_handle_t input) = 0; . virtual audio_module_handle_t loadHwModule(const char *name) = 0;/加載Interface . ; IAudioFlinger定義了AudioFlinger服務的基本業務函數。我們從中可以看到,它定義了加載Audio Interface、音量設置、音頻設備屬性獲取(采樣率、幀信息)、打開音頻設備輸入、輸出流等函數。AudioFlinger是IAudioFlinger的服務端實現,它必定要實現IAudioFlinger中的接口;

25、我們這里只看一些它添加的主要函數定義:cpp view plain copy 在CODE上查看代碼片派生到我的代碼片ThreadBase *checkThread_l(audio_io_handle_t ioHandle) const; PlaybackThread *checkPlaybackThread_l(audio_io_handle_t output) const; MixerThread *checkMixerThread_l(audio_io_handle_t output) const; RecordThread *checkRecordThread_l(audio_io_ha

26、ndle_t input) const; sp openInput_l(audio_module_handle_t module, audio_io_handle_t *input, audio_config_t *config, audio_devices_t device, const String8& address, audio_source_t source, audio_input_flags_t flags); sp openOutput_l(audio_module_handle_t module, audio_io_handle_t *output, audio_config

27、_t *config, audio_devices_t devices, const String8& address, audio_output_flags_t flags); void closeOutputFinish(sp thread); void closeInputFinish(sp thread); / no range check, AudioFlinger:mLock held bool streamMute_l(audio_stream_type_t stream) const return mStreamTypesstream.mute; / no range chec

28、k, doesnt check per-thread stream volume, AudioFlinger:mLock held float streamVolume_l(audio_stream_type_t stream) const return mStreamTypesstream.volume; void ioConfigChanged(audio_io_config_event event, const sp& ioDesc, pid_t pid = 0); / Allocate an audio_unique_id_t. / Specific types are audio_i

29、o_handle_t, audio_session_t, effect ID (int), / audio_module_handle_t, and audio_patch_handle_t. / They all share the same ID space, but the namespaces are actually independent / because there are separate KeyedVectors for each kind of ID. / The return value is cast to the specific type depending on

30、 how the ID will be used. / FIXME This API does not handle rollover to zero (for unsigned IDs), / or from positive to negative (for signed IDs). / Thus it may fail by returning an ID of the wrong sign, / or by returning a non-unique ID. / This is the internal API. For the binder API see newAudioUniq

31、ueId(). audio_unique_id_t nextUniqueId(audio_unique_id_use_t use); status_t moveEffectChain_l(audio_session_t sessionId, PlaybackThread *srcThread, PlaybackThread *dstThread, bool reRegister); / return thread associated with primary hardware device, or NULL PlaybackThread *primaryPlaybackThread_l()

32、const; audio_devices_t primaryOutputDevice_l() const; / return the playback thread with smallest HAL buffer size, and prefer fast PlaybackThread *fastPlaybackThread_l() const; sp getEffectThread_l(audio_session_t sessionId, int EffectId); AudioFlinger中定義了許多跟PlaybackThread有關的函數。PlaybackThread是回放線程,定義

33、在Thread.h中;它是AudioFlinger中真正處理音頻數據的結構,擔任一個任勞任怨的工人角色;PlaybackThread家族還有許多其他的線程子類,它們都對應著一個不同的音頻數據處理場景。PlaybackThread相關的內容,后續分析到真正的音頻數據處理時在介紹。AudioFlinger中定義了幾個內部類:cpp view plain copy 在CODE上查看代碼片派生到我的代碼片/ server side of the clients IAudioTrack class TrackHandle : public android:BnAudioTrack /使用AudioTra

34、ck時會涉及 public: TrackHandle(const sp& track); virtual TrackHandle(); virtual sp getCblk() const; virtual status_t start(); virtual void stop(); virtual void flush(); virtual void pause(); virtual status_t attachAuxEffect(int effectId); virtual status_t setParameters(const String8& keyValuePairs); vir

35、tual status_t getTimestamp(AudioTimestamp& timestamp); virtual void signal(); / signal playback thread for a change in control block virtual status_t onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags); private: const sp mTrack; ; / server side of the clients IAudioRecord c

36、lass RecordHandle : public android:BnAudioRecord /使用AudioRecord時,會涉及 public: RecordHandle(const sp& recordTrack); virtual RecordHandle(); virtual status_t start(int /*AudioSystem:sync_event_t*/ event, audio_session_t triggerSession); virtual void stop(); virtual status_t onTransact( uint32_t code, c

37、onst Parcel& data, Parcel* reply, uint32_t flags); private: const sp mRecordTrack; / for use from destructor void stop_nonvirtual(); ; TrackHandler在分析AudioTrack的時候會介紹;RecordHandler也是如此。另外,AudioFlinger中還有幾個重要的集合對象:cpp view plain copy 在CODE上查看代碼片派生到我的代碼片/保存Audio Interface的一些信息 DefaultKeyedVector mAudi

38、oHwDevs; /保存創建的PlaybackThread工作線程 DefaultKeyedVector audio_io_handle_t, sp mPlaybackThreads; /保存創建的RecordThread錄音工作線程 DefaultKeyedVector audio_io_handle_t, sp mRecordThreads 這幾個集合對象在后續的分析中都會遇到有了對AudioFlinger定義的認識,我們再看它的構造函數。注冊AudioFlinger服務時,會創建一個它的實例;此時會調用其構造函數:cpp view plain copy 在CODE上查看代碼片派生到我的代

39、碼片AudioFlinger:AudioFlinger() : BnAudioFlinger(), mPrimaryHardwareDev(NULL), mAudioHwDevs(NULL), mHardwareStatus(AUDIO_HW_IDLE), mMasterVolume(1.0f), mMasterMute(false), / mNextUniqueId(AUDIO_UNIQUE_ID_USE_MAX), mMode(AUDIO_MODE_INVALID), mBtNrecIsOff(false), mIsLowRamDevice(true), mIsDeviceTypeKnow

40、n(false), mGlobalEffectEnableTime(0), mSystemReady(false) / unsigned instead of audio_unique_id_use_t, because + operator is unavailable for enum for (unsigned use = AUDIO_UNIQUE_ID_USE_UNSPECIFIED; use AUDIO_UNIQUE_ID_USE_MAX; use+) / zero ID has a special meaning, so unavailable mNextUniqueIdsuse

41、= AUDIO_UNIQUE_ID_USE_MAX; getpid_cached = getpid(); const bool doLog = property_get_bool(ro.test_harness, false); if (doLog) mLogMemoryDealer = new MemoryDealer(kLogMemorySize, LogWriters, MemoryHeapBase:READ_ONLY); / reset battery stats. / if the audio service has crashed, battery stats could be l

42、eft / in bad state, reset the state upon service start. BatteryNotifier:getInstance().noteResetAudio(); #ifdef TEE_SINK char valuePROPERTY_VALUE_MAX; (void) property_get(ro.debuggable, value, 0); int debuggable = atoi(value); int teeEnabled = 0; if (debuggable) (void) property_get(af.tee, value, 0);

43、 teeEnabled = atoi(value); / FIXME symbolic constants here if (teeEnabled & 1) mTeeSinkInputEnabled = true; if (teeEnabled & 2) mTeeSinkOutputEnabled = true; if (teeEnabled & 4) mTeeSinkTrackEnabled = true; #endif AudioFlinger的構造函數并沒有做某些復雜的初始化操作,都是一些簡單的成員變量賦值等。基于Android強弱指針的知識,我們知道一個對象被sp引用時,會調用它的on

44、FirstRef()函數。AudioFlinger也是這樣,它的onFirstRef()實現是:cpp view plain copy 在CODE上查看代碼片派生到我的代碼片void AudioFlinger:onFirstRef() Mutex:Autolock _l(mLock); /* TODO: move all this work into an Init() function */ char val_strPROPERTY_VALUE_MAX = 0 ; if (property_get(ro.audio.flinger_standbytime_ms, val_str, NULL) = 0) uint32_t int_val; if (1 = sscanf(val_str, %u, &int_val) mStandbyTimeInNsecs = milliseconds(int_val); ALOGI(Using %u mSec as standby time., int_val); else mStandbyTimeInNsecs = kDefaultStandb

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論