背景
以下內(nèi)容基于Android P code。
應(yīng)用框架設(shè)計
Android電話模塊是一個典型的分層結(jié)構(gòu)設(shè)計,如下:

IMS在CS通話的基礎(chǔ)上增加了telephony/ims net/ims vendor/ims 和ims相關(guān)的media模塊。
其中:
telephony/ims:主要包括了對外接口ImsPhone,通話管理中心ImsPhoneCallTracker,某一路通話ImsPhoneCall,某一路通話連接ImsPhoneConnection。需要實現(xiàn)的提供IMS相關(guān)服務(wù)的ImsService。
net/ims:主要包括提供了IMS services API的ImsManager,以及ImsManager創(chuàng)建的負(fù)責(zé)處理 IMS語音和視頻通話連接的ImsCall。
vendor/ims:主要包括了ImsService的實現(xiàn)類,提供ims相關(guān)的服務(wù)。負(fù)責(zé)和modem和media打交道,這一模塊由各個芯片廠商定制,所以各個芯片廠商的實現(xiàn)方式都不同。但都有一個實現(xiàn)?ImsService的類。
IMS service
IMS的服務(wù)類,telephony通過ImsResolver來和綁定它。它的實現(xiàn)類必需在AndroidManifest中對它進(jìn)行注冊以便fw檢測到它。
其主要結(jié)構(gòu)如下:

主要包括 ImsService、ImsManager、MmTelFeatureConnection、ImsCallSession。其中:
ImsService:ims的Service,實現(xiàn)了所有的ImsFeature(MmTelFeature和RcsFeature)和ims協(xié)議行為。通過ImsResolver綁定。由ImsServiceController來負(fù)責(zé)管理其生命周期及這個service所支持的ImsFeatures。其主要操作可以通過IImsServiceController來調(diào)用。
ImsManager:單例類。提供了與IMS services交互的API,如創(chuàng)建ims call。這個類是所有ims相關(guān)操作的起點。
MmTelFeatureConnection:IImsServiceController binder的容器類。
ImsCallSession:負(fù)責(zé)ImsCall的發(fā)起和終止,以及兩個ims端點間的媒體交換。它和ImsService直接交互。
其service的綁定過程如下:

可以看到,phone進(jìn)程在創(chuàng)建后由ImsResolver通過ImsServiceController來綁定service,service返回IImsServiceController給ImsServiceController,然后通過這個binder來創(chuàng)建IImsMmTelFeature的binder。之后可以通過TelephonyManager來獲取IImsMmTelFeature的binder,用它可以獲取IImsCallSession的binder。
具體的綁定流程如下:

應(yīng)用間進(jìn)程交互
交互方式如下:

在android o之前phone和ril的交互是通過socket,android o之后改成了HIDL。其余進(jìn)程間的交互都是通過AIDL,具體交互方式如圖:

其中,phone到modem的過程,CS Call是由RILRequest通過HIDL調(diào)用IRadio.hal再到modem,IMS Call是由ImsCallSession通過AIDL調(diào)用ImsCallSessionImpl再通過HIDL調(diào)用IImsRadio.hal再到modem。而modem到phone的過程,CS Call是由IRadioResponse.hal通過HIDL非主動上報結(jié)果給RadioResponse,而IRadioIndication.hal通過HIDL主動上報通知給RadioIndication,IMS Call則是從hal上報到Ims service,再通過ImsCallSessionListener通知到ImsCallSession。
總的來說就是IMS Call比CS Call在phone進(jìn)程和ril hal中多了一層ims service。
通話流程
IMS Call結(jié)構(gòu)
先看CS Call和IMS Call的結(jié)構(gòu)對比:

從圖中可以看出,其實整體的設(shè)計模式差不多。其對比如下:
1. 對外接口GsmCdmaPhone對應(yīng)ImsPhone。
2. 一路通話的封裝類GsmCdmaCall對應(yīng)ImsPhoneCall。
3. 通話中的某路連接GsmCdmaConnection對應(yīng)ImsPhoneConnection。
4. modem返回回來的某一路通話連接DriverCall對應(yīng)ImsCall。
5. CS Call phone 通過IRadio、IRadioResponse、IRadioIndication和RIL交互。
6. IMS Call phone 通過IImsCallSession、IImsCallSessionListener、IImsMmTelListener和ims service交互。
IMS Call MO流程
先看IMS和CS的對比:

可以看到CallTracker撥號之前的過程兩者一樣,CallTracker撥號時CS Call直接通過RIL用HIDL來調(diào)用IRadio.hal撥號;而IMS Call需要由ImsManager通過ImsCallSession用AIDL調(diào)用ImsCallSessionImpl,再通過HIDL調(diào)用IImsRadio.hal來撥號,比CS Call多了ims service進(jìn)程中的處理。
CallTracker撥號之前的過程可以參考我之前的文章?Android通話應(yīng)用設(shè)計,其大致流程沒有變。這里補(bǔ)充一下telecom進(jìn)程撥號的具體細(xì)節(jié)如下:
其大至流程就是:

1. 撥號應(yīng)用如Dialer調(diào)用TelecomManager#placeCall()。
2. CallsManager#startOutgoingCall()創(chuàng)建Call,并設(shè)置Call狀態(tài)為Connecting。判斷是否mmi code,如果不是通知InCallUI更新界面。
3. 發(fā)送order broadcast給接收該廣播的應(yīng)用更改號碼相關(guān)信息。
4. CallsManager#placeOutgoingCall()根據(jù)intent中所帶參數(shù)判斷該通電話是否為視頻電話.
5. 建立同ConnectionService的連接,通知TelephonyConnectionService撥號。
6.?TelephonyConnectionService通知撥號成功,更新Call狀態(tài)為Dialing。
其中IMS Call增加的流程就是在撥號時的intent中帶參數(shù)配置該通電話是否為視頻電話,然后把這個videoState一直傳遞下去。
IMS Call 狀態(tài)變更流程
先看IMS和CS的對比:

和MO一樣,IMS Call多了ims service這一部分,而CS Call 多了GET_CURRENT_CALLS的過程。
其中的重點部分是IMS Call 中的ImsPhoneCallTracker#processCallStateChange()及CS Call 中的GsmCdmaCallTracker#handlePollCalls()。
和app相關(guān)的流程請參考?Android通話應(yīng)用設(shè)計。
IMS Call MT流程
先看IMS和CS的對比:

其對比如下:
1.?CS Call 在收到RadioIndication上報的callStateChanged()后會通過GET_CURRENT_CALL來更新DriverCall,?然后在GsmCdmaCallTracker#handlePollCalls()中通過DriverCall來更新Connection并通知app來電。
2. IMS Call 中會在ImsPhoneCallTracker#onIncomingCall()中通過ImsCallSession來創(chuàng)建ImsCall連接,并創(chuàng)建Connection,創(chuàng)建Connection時會通過IImsCallSession里帶的參數(shù)判斷通話是否為視頻通話。
app來電后的流程可參考?Android通話應(yīng)用設(shè)計,這里補(bǔ)充telecom app 來電的流程,如下:

1. telephony收到來電通知時根據(jù)來電的phone找到PhoneAccountHandle,通話TelecomManager#processIncomingCallIntent()通知telecom來電。
2. CallsManager#processIncomingCallIntent()創(chuàng)建Call,并建立和ConnectionService的連接。
3. ConnectionService返回連接成功,通過phone進(jìn)程中的Connection更新telecom/Call,包括是否視頻電話。
4. CallsManager#onSuccessfulIncomingCall()開始號碼過濾查詢(包括黑名單查詢),如果是過濾號碼來電直接拒接。
5. 如果是非過濾號碼來電更新Call狀態(tài)為RINGING。
6. 通過InCallController建立與通話界面的連接,更新通話界面。
MMI Code 流程
MMI:Man-Machine-Interface,人機(jī)界面,所有帶*或#的號碼都是MMI Code。通常以*、#、*#、**、##等開頭,以#號結(jié)束,各個部分以*隔開。它們有些僅在設(shè)備上使用,有些發(fā)送給sim卡處理,有些則發(fā)給運(yùn)營商網(wǎng)絡(luò)處理。它主要分為:
1. USSD:Unstructured Supplementary Service Data,非結(jié)構(gòu)化補(bǔ)充服務(wù)數(shù)據(jù)碼,發(fā)送給網(wǎng)絡(luò)處理。所有以#號結(jié)尾且沒有被識別為MMI Code的號碼都會被發(fā)送到網(wǎng)絡(luò)來確認(rèn)該號碼是否為運(yùn)營商支持的USSD。
2. SS:Supplementary Service,補(bǔ)充服務(wù)碼,發(fā)送給網(wǎng)絡(luò)處理。如*21*xxx xxxx xxxx#為GSM/UMTS/LTE網(wǎng)絡(luò)的來電轉(zhuǎn)接碼,這個號碼會由手機(jī)轉(zhuǎn)換成網(wǎng)絡(luò)可識別的來電轉(zhuǎn)接碼。
3. Manufacturer defined MMI codes:手機(jī)廠商自定義的mmi碼,在設(shè)備上執(zhí)行。如通用的*#06#會顯示手機(jī)IMEI號。各家手機(jī)廠商也可以定義自己的mmi碼來做為暗碼,它的處理一般在Dialer/SpeciaCharSequenceMgr中。
4. SIM control codes:sim卡控制碼,發(fā)送給sim卡處理。如**04*1234*6789*6789#會把sim卡的pin碼從1234改成6789。
MMI code 分主動上報和非主動上報兩種,下圖為非主動手報流程:

1. 手機(jī)自己處理的mmi碼一般直接通過Dialer處理。
2. 發(fā)送給sim卡處理的碼通過Dialer直接傳到GsmMmiCode給UiccCardApplication再由IRadio.hal處理,其處理結(jié)果會在PhoneUtils#displayMMIComplete()顯示給用戶。
3. 發(fā)送給網(wǎng)絡(luò)處理的碼則和正常撥號一樣,只不過telecom在判斷其為mmi code后不會通知InCallUI,CallTracker#dial()后返回空的Connection給phone app通知其彈出對話框提示用戶正在進(jìn)行MMI碼的處理。
4. 會先判斷該mmi code是不是ims網(wǎng)絡(luò)的碼,如果是直接由ims網(wǎng)絡(luò)處理,如果不是則由gsm/umts/lte網(wǎng)絡(luò)處理。
5. SS code手機(jī)能直接判斷出,然后轉(zhuǎn)換為網(wǎng)絡(luò)能識別的命令發(fā)送給網(wǎng)絡(luò),CS Call和通話一樣由IRadio.hal處理,而IMS Call則不是由IImsCallSession處理而是通過IImsUt處理。USSD code直接透傳給網(wǎng)絡(luò)處理。網(wǎng)絡(luò)處理結(jié)果CS Call和通話狀態(tài)一樣直接由IRadioResponse.hal通知,IMS Call則由IImsUtListener通知。
原創(chuàng)內(nèi)容歡迎轉(zhuǎn)載,但請注明出處,謝謝!