1. 程式人生 > >MTK IMS框架簡析(1)——程式碼架構及模組初始化

MTK IMS框架簡析(1)——程式碼架構及模組初始化

1.前言

隨著4G技術的誕生和國內運營商網路的全面升級,以往流量貴上網慢的問題不再有,而類似微信這類即時通訊軟體也得到快速的普及,網際網路行業的發展還延伸到金融/零售等線上線下的各行各業,短短几年內國內IT產業迎來全面的機遇。而得益於移動網路技術的突破,政策的開放和喬幫主的1%的智慧,成就了今天高效的網際網路+社會。

4G協議中定義了包含volte和RCS等基於運營商核心網實現的功能,將發揮網速優勢消滅CS域,同時提供高清語音通話和多媒體IM通訊功能,當年還在賣簡訊掙錢的運營商們想到這些肯定心理暗爽。但實際成本高昂,除了要進一步升級核心網,還要聯合晶片商和終端廠商合作開發或整合volte和RCS方案才能產生威力,而且體驗也是一個大問題,因此對此支援少之又少,目前深圳只有中移動支援volte,但瞭解和使用的人其實不多。

中國移動早年開始搗鼓Ophone的時候(欲通過4G升級佔領終端繼延續統治),第三方軟體廠們已經發力開始在IM上廝殺,一向財大氣粗運營商們眼看著江山四分五裂,又只能靠賣流量賣手機甚至賣寬頻來搶客戶了。。。

言歸正傳,目前高通和MTK等晶片大廠都已完美支援volte,就以MTK為例分析下功能實現。

2. 程式碼結構

MTKIMS相關程式碼由4部分構成,有Google新增的框架,和MTK實現的Service部分:

//原有框架中拓展出ims相關類,如ImsPhone/ImsPhoneCallTracker/ImsCallConnection/ImsPhoneCall等
/frameworks/opt/telephony/src/java/com/android/internal
/telephony/imsphone //實現了Parcelable的公共類,和一些aidl介面 /frameworks/base/telephony/java/com/android/ims //為Ims服務提供介面,ImsManager提供通話/開關volte/更新和獲取ims狀態等介面。 /frameworks/opt/net/ims/ //mtk實現部分,實現了與rild-ims的對接方式ims CommandsInterface實現 /vendor/mediatek/proprietary/packages/services/Ims/

接下來依次分析以上4個目錄的架構和職責。

telephony框架

/frameworks/opt/telephony/src/java/com/android/internal/telephony/imsphone
此部分程式碼主要為volte通話功能新增


ImsPhone為在PhoneBase的子類,而PhoneBase直接持有ImsPhone的例項,在原有的GsmPhone和CdmaPhone類中增加對ims的判斷,例如撥號方法dial中,會先判斷當前是否支援volte,再決定使用imsPhone的dial還是的當前phoneBase中的dial方法。

為什麼不把ImsPhone像GsmPhone和CdmaPhone那樣獨立出來?
這樣設計可能更精簡。對於telephony框架新增的部分只涉及到通話功能,且Volte只作為一個可選業務,基於當前網路的資料業務承載,這樣設計只需要在原來GsmPhone和CdmaPhone通話相關的介面加入volte的判斷即可。
這裡寫圖片描述

上圖看到架構基本與GsmPhone/CdmaPhone一致,都有CallTracker / Connection / Call / Phone,ImsPhoneCallTracker擁有ImsManager例項,總管電話業務,負責執行操作和更新電話狀態。而ImsPhone是這一層的管家,掌握通話的控制入口ImsPhoneCallTracker,實時關注Service state,上報狀態到應用層等。

opt/net/ims

/frameworks/opt/net/ims/更像中間層的處理,只向上提供介面。
ImsManager就是提供IMS操作介面的類,介面功能包括開關volte功能 / 打電話 / 設定補充業務(來電轉駁等) / 設定IMS服務屬性 (但不包括短彩信操作) 等等。
ImsManager.java中的一段說明:

/**
 * Provides APIs for IMS services, such as initiating IMS calls, and provides access to
 * the operator's IMS network. This class is the starting point for any IMS actions.
 **/
ImsManager是IMS服務的起始點,併為IMS服務提供介面,如建立通話和接入ims網路等。

ImsManager成員及作用:
1. IImsService —— aidl例項,負責ims服務狀態相關的操作。
2. ImsCall和ImsCallSession —— 負責通話的建立和狀態跟蹤,通過listener來同步訊息,對接com.mediatek.ims中的ImsCallSessionProxy。
3. ImsUt —— 負責補充業務,對接ImsUtStub。
4. ImsConfig —— 負責IMS功能設定,對接ImsConfigImpl。

明顯看到,opt/net/ims這一層只提供介面,對接packages/services/Ims/並由它來實現具體的業務。

這裡寫圖片描述

ims app

/vendor/mediatek/proprietary/packages/services/Ims/ 以app形式存在,主要負責具體業務的執行,與rild和庫對接。

ImsRILAdapter——CommandsInterface介面的實現者,與RIL.java設計類似,有ImsRILSender和ImsRILReceiver在各自執行緒中執行收發,和rild-ims互動;

ImsService —— 管理ims服務狀態,提供狀態的get介面,執行ims註冊 / 建立通話 等操作。

ImsCallSessionProxy —— 負責執行通話相關操作,直接與ImsRILAdapter互動,並通過Listener上報狀態。

ImsConfigImpl —— 負責執行設定的操作,直接與ImsRILAdapter互動。

ImsUtStub —— 負責補充業務的設定,特殊的是並不通過ImsRILAdapter執行,而是單獨實現的路徑。

ImsAdapter —— MTK封裝了一些處理到volte_imsm.so,ImsAdapter負責對接這個庫,這個類的用途就是單獨處理MTK不開源的部分;ImsEventDispatcher將volte_imsm上報的訊息分發給實現了VaEventDispatcher的類:DataDispatcher——負責ims連線管理(如發起data call);CallControlDispatcher負責volte call相關。

(工程中查詢volte_imsm.so,發現MTK並沒有開源:vendor/letv/libs/mt6797_64/volte_imsm/)

這裡寫圖片描述

framework中相關公共類和aidl定義

/frameworks/base/telephony/java/com/android/ims
frameworks/base…/ims下定義了一些可以公用的類,都屬於特定資料的封裝,基本上都繼承了aidl stub跨程序無壓力。

internal包下還定義了一系列aidl檔案,具體實現都在/vendor/mediatek/proprietary/packages/services/Ims/中,為其提供訪問入口。
這裡寫圖片描述

3. 模組的初始化

以上模組在開機後即開始初始化過程,下面來看下它們如何開始初始化。

mtk ims應用初始化

/vendor/mediatek/…/services/Ims/ 在AndroidManifest中定義了application的persistent為true,因此ims app開機即自動載入:

<application android:name="ImsApp" 
             android:persistent="true">
        ...
</application>

ImsApp在onCreate方法中建立ImsService例項,並將其新增為系統服務:

public class ImsApp extends Application {
    public ImsApp() {
    }

    @Override
    public void onCreate() {
        if (UserHandle.myUserId() == 0) {

            ImsService imsService = new ImsService(this);
            ServiceManager.addService(ImsManager.IMS_SERVICE, imsService.asBinder(), true);
        }
    }
}

而ImsAdapter / ImsRILAdapter及ImsConfigImpl等例項在ImsService構造方法中建立。

public ImsService(Context context) {
        //初始化ImsAdapter和ImsRILAdapter例項
        mImsAdapter = new ImsAdapter(context);
        mImsRILAdapter = new ImsRILAdapter(context);
        mContext = context;
        mHandler = new MyHandler();

        ...
        //建立ImsConfigImpl例項
        if (SubscriptionManager.isValidPhoneId(mainPhoneId)) {
            synchronized (this) {
                ImsConfigImpl instance = new ImsConfigImpl(mContext, mImsRILAdapter, mainPhoneId);
                mImsConfigInstanceMap.put(mainPhoneId, instance);
            }
        }
        //註冊ims及radio狀態監聽
        mImsRILAdapter.registerForImsRegistrationInfo(mHandler, EVENT_IMS_REGISTRATION_INFO, null);
        mImsRILAdapter.registerForImsEnableStart(mHandler, EVENT_IMS_ENABLING_URC, null);
        mImsRILAdapter.registerForImsEnableComplete(mHandler, EVENT_IMS_ENABLED_URC, null);
        mImsRILAdapter.registerForImsDisableStart(mHandler, EVENT_IMS_DISABLING_URC, null);
        mImsRILAdapter.registerForImsDisableComplete(mHandler, EVENT_IMS_DISABLED_URC, null);
        mImsRILAdapter.setOnIncomingCallIndication(mHandler, EVENT_INCOMING_CALL_INDICATION, null);
        mImsRILAdapter.setOnCallRing(mHandler, EVENT_CALL_RING, null);
        mImsRILAdapter.registerForCallProgressIndicator(mHandler, EVENT_SIP_CODE_INDICATION, null);
        /// register for radio state changed
        mImsRILAdapter.registerForNotAvailable(mHandler, EVENT_RADIO_NOT_AVAILABLE, null);
        //mImsRILAdapter.registerForOff(mHandler, EVENT_RADIO_OFF, null);
        mImsRILAdapter.registerForOn(mHandler, EVENT_RADIO_ON, null);

        ...
    }

框架層初始化

ImsPhone的存活由ImsService的2個廣播訊息決定。
一切從PhoneBase::makeDefaultPhone方法開始,在建立GSMPhone和CDMAPhone後,呼叫startMonitoringImsService方法監控IMS狀態。

for (int i = 0; i < numPhones; i++) {
    PhoneBase phone = null;
    int phoneType = TelephonyManager.getPhoneType(networkModes[i]);
    if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
        phone = new GSMPhone(context,
                  sCommandsInterfaces[i], sPhoneNotifier, i);
        phone.startMonitoringImsService();
    } else if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
        phone = new CDMALTEPhone(context,
                                sCommandsInterfaces[i], sPhoneNotifier, i);
        phone.startMonitoringImsService();
    }
    sProxyPhones[i] = new PhoneProxy(phone);
}

startMonitoringImsService中做了3件事:
1. 註冊receiver監聽IMS_SERVICE_UP和IMS_SERVICE_DOWN訊息
2. 初始化了ImsManager
3. 如果檢查到ImsService已經啟動,即呼叫updateImsPhone

public void startMonitoringImsService() {
        ...
        synchronized(PhoneProxy.lockForRadioTechnologyChange) {
            IntentFilter filter = new IntentFilter();
            filter.addAction(ImsManager.ACTION_IMS_SERVICE_UP);
            filter.addAction(ImsManager.ACTION_IMS_SERVICE_DOWN);
            mContext.registerReceiver(mImsIntentReceiver, filter);
            mImsIntentReceiverRegistered = true;
            ImsManager imsManager = ImsManager.getInstance(mContext, getPhoneId());
            if (imsManager != null && imsManager.isServiceAvailable()) {
                mImsServiceReady = true;
                updateImsPhone();
            }
        }
    }

updateImsPhone方法需要判斷mImsServiceReady標誌決定建立或銷燬ImsPhone。mImsServiceReady標誌取值由誰決定?這裡先回頭看在mImsIntentReceiver能否找到答案。

PhoneBase.java
protected void updateImsPhone() {
        if (mImsServiceReady && (mImsPhone == null)) {
            mImsPhone = PhoneFactory.makeImsPhone(mNotifier, this);
            CallManager.getInstance().registerPhone(mImsPhone);
        } else if (!mImsServiceReady && (mImsPhone != null)) {
            mImsPhone.unregisterForSilentRedial(this);
            mImsPhone.dispose();
            mImsPhone = null;
        }
    }

答案果然就在mImsIntentReceiver這個receiver處理中,IMS_SERVICE_UP和IMS_SERVICE_DOWN訊息決定著mImsServiceReady的值。
IMS_SERVICE_UP和IMS_SERVICE_DOWN訊息直接對應著ImsRilAdapter的RIL_UNSOL_IMS_ENABLE_DONE和RIL_UNSOL_IMS_DISABLE_DONE訊息,在開啟/關閉IMS服務後上報。

private BroadcastReceiver mImsIntentReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            ...
            synchronized (PhoneProxy.lockForRadioTechnologyChange) {
                if (intent.getAction().equals(ImsManager.ACTION_IMS_SERVICE_UP)) {
                    mImsServiceReady = true;
                    updateImsPhone();
                    ImsManager.updateImsServiceConfig(mContext, mPhoneId, false);
                } else if (intent.getAction().equals(ImsManager.ACTION_IMS_SERVICE_DOWN)) {
                    mImsServiceReady = false;
                    updateImsPhone();
                }
            }
        }
    };

因此,ImsPhone初始化需要2個條件:1. ImsService已啟動,2. ims ril上報RIL_UNSOL_IMS_ENABLE_DONE。

rild-ims

MTK單獨提供socket來專門處理ims訊息。
init.rc中的描述:

service ril-daemon-mtk /system/bin/mtkrild
    class core
    socket rild stream 660 root radio
    socket rild2 stream 660 root radio
    socket rild3 stream 660 root radio
    socket rild4 stream 660 root radio
    #rild-ims 相關socket
    socket rild-ims stream 660 root radio 
    socket rild-debug stream 660 radio system
    socket rild-oem stream 660 radio system
    socket rild-mtk-ut stream 660 radio net_bt
    socket rild-mtk-ut-2 stream 660 radio net_bt
    socket rild-mtk-modem stream 660 radio system
    socket rild-atci stream 660 root radio
    socket rild-mal stream 660 radio system
    socket rild-mal-at stream 660 radio system
    socket rild-vsim stream 660 root radio
    socket rild-mbim stream 660 root radio
    socket sap_uim_socket1 stream 660 bluetooth bluetooth
    socket sap_uim_socket2 stream 660 bluetooth bluetooth
    user root
    group radio cache inet misc audio sdcard_r sdcard_rw log system
    disabled
    oneshot

小結

google為IMS擴充套件了framework處理並向上提供了介面,而MTK實現了ims app(vendor目錄),對接so庫和rild的核心邏輯。

後續有空再分析ims業務的註冊流程,還有volte的通話流程。

相關推薦

MTK IMS框架1——程式碼架構模組初始

1.前言 隨著4G技術的誕生和國內運營商網路的全面升級,以往流量貴上網慢的問題不再有,而類似微信這類即時通訊軟體也得到快速的普及,網際網路行業的發展還延伸到金融/零售等線上線下的各行各業,短短几年內國內IT產業迎來全面的機遇。而得益於移動網路技術的突破,政策的

第五節:JQuery框架源碼1

err cal content browser active lac rda setting right (轉自老惠的博客) JQuery是一個應用廣泛、非常優秀的JavaScript框架,其代碼簡潔而優雅,有很多值得我們學習的地方。這裏僅僅對其代碼結構做一個簡單的分析

sam 百度面經中的問題 1

表單提交中get和post方式的區別有5點  1.get是從伺服器上獲取資料,post是向伺服器傳送資料。  2.get是把引數資料佇列加到提交表單的ACTION屬性所指的URL中,值和表單內各個欄位一一對應,在URL中可以看到。post是通過HTTPpost機制,將表單內各個欄位與其內容放置在HTML H

基於springboot2 框架整合1:spring boot專案初始

前言 專案中使用了很多現成的框架,都是專案經理、架構師帶來的,從來沒有自己整合過!這次決定自己從零開始整合一次,以學習鞏固。過程中參考很多開源框架的思路,工具類等,若有侵權,請速速聯絡,一定妥善處理   一:建立maven專案 這個不多說,給出pom.xml

走進webpack1--環境拆分模塊

進階 相關 詳細 package 例子 互斥 ecif 是把 文件   初級的文章和demo已經基本完成了,代碼也已經上傳到了我的github上,如果你對webpack的使用並不是十分了解,那麽建議你回頭看下走近系列,裏面包括了當前項目中使用頻繁的插件,loader的講解。

【DirectX11】【學習筆記1番外練習】初始DirectX11

繼續上一章提到的錯誤checking HRESULT值: S_OK - 函式成功 E_NOTIMPL - 函式沒有執行 E_NOINTERFACE - 介面不支援 E_ABORT - 函式越界 E_FAIL - 函式失敗 E_INVALIDARG - 一個或者多

tensorflow基礎1變數的建立、初始、儲存與載入

廢話就不多說了,直接上乾貨。 1.變數的建立 tensoflow建立變數使用tf.Variable();需要指明變數的形狀 b = tf.Variable(tf.zeros([1])) W = tf.Variable(tf.random_uniform([

【開源】OSharp框架學習系列1:總體設計系列導航

正是 html 組織 內聚性 權限 是什麽 enc 3-0 分發 OSharp是什麽?   OSharp是個快速開發框架,但不是一個大而全的包羅萬象的框架,嚴格的說,OSharp中什麽都沒有實現。與其他大而全的框架最大的不同點,就是OSharp只做抽象封裝,不做實現。依賴註

asp.net -mvc框架復習1-ASP.NET網站開發概述

頁面設計 對象 ado 數據庫開發 sqlserve 網站 rip ado.net 面向對象 1.網站開發的基本步驟: 2.網站開發的需要的知識結構 (1)網站開發前臺頁面技術 頁面設計:HTML 、CSS+DIV 頁面特效:JavaScript、jQery (2)

深度學習解決局部極值和梯度消失問題方法轉載

復雜度 現實 概率 傳播 相同 證明 dap 很難 卷積神經網絡 轉載:http://blog.sina.com.cn/s/blog_15f0112800102wojj.html 這篇文章關於對深度CNN中BP梯度消失的問題的做了不錯的解析,可以看一下: 多層感知機解決

豹哥嵌入式講堂:ARM Cortex-M調試過程探1- 4線接口標準JTAG

狀態機 alt 端口 含義 允許 ati state 數據 identity   大家好,我是豹哥,獵豹的豹,犀利哥的哥。今天豹哥給大家講的是嵌入式調試裏的接口標準JTAG。   在結束《ARM Cortex-M開發文件詳解》系列文章之後,豹哥修整了一小段時間,但是講課的

TensorFlow框架實戰學習1

msu HA gin PE var shape highlight padding lin 1 import tensorflow as tf 2 import numpy as np 3 import matplotlib.pyplot as plt 4

Vue框架入門筆記1

rip com PE charset oct div 筆記 AR body <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> &l

Yii框架學習入門1--YII的MVC概念邏輯解析

YII的MVC概念及邏輯解析1、這裏是win10安裝的是Yii2.0,中文社區:http://www.yiichina.com/ 。2、先了解安裝方法:服務器用的是wamp,將Yii2.0高級版解壓文件放入www目錄,將php加入全局命令(右擊【計算機】-【屬性】-【高級系統設置】然後在系統屬性裏選擇【高級】

從零寫分散式RPC框架 系列 第一版 1架構設計

本系列文章的目的是搭建出一個基於Netty,Zookeeper和SpringBoot的簡易分散式RPC框架,並且釋出到Maven中央倉庫以 spring-boot-starter 的形式對外提供開箱即用的服務。1.0 版本使用 protobuf 來做序列化,最終的使用形式比較接近於 Du

框架綜合實踐1-driver的封裝capability

讀取yaml配置檔案: 有兩種方式,一個是file open,一個是with open 方式1 file = open('../config/WiFibanlv_caps.yaml', 'r') data = yaml.load(file) file.close() #必須使用clo

Spring框架的初識1spring的簡介, IOC操作

一.什麼是Spring框架 1.spring是開源的輕量級框架 2.spring是一站式框架 (1)spring在javaee三層結構中,每一層都提供不同的解決技術 - web層:springMVC - service層:spring的ioc

Linux VFS機制

Linux VFS機制簡析(二) 接上一篇Linux VFS機制簡析(一),本篇繼續介紹有關Address space和address operations、file和file operations、dentry和dentry operations和dentry cache API。 Address Sp

排程框架學習筆記1

參考資料: 計算架構:分散式排程技術演變 叢集資源管理與排程概要 1 知識點 1.1 什麼是排程 通常所說的排程(schedule)是和時間有關的。 單 CPU 的時間片排程 時間作為唯一的不可逆轉的資源,一般是劃分為多個時間片來使用。就計算機而言,由於 CPU 的速度快的多,所以就有了針對 C

地圖視覺框架新進展1

1. Uber視覺化框架 Uber目前有一整套地圖視覺化框架,有: deck.gl :高效能WebGL地理圖層和資訊視覺化用例 react-map-gl:用於Mapbox GL的React元件(與deckgl無縫整合) react-vis:一套基於Rea