MTK IMS框架简析(1)——代码架构及模块初始化

来源:互联网 发布:高考作文书推荐 知乎 编辑:程序博客网 时间:2024/06/05 11:55

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/
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

接下来依次分析以上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网络等。
  • 1
  • 2
  • 3
  • 4
  • 5

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>
  • 1
  • 2
  • 3
  • 4

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);        }    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

而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);        ...    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

框架层初始化

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);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

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();            }        }    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

updateImsPhone方法需要判断mImsServiceReady标志决定创建或销毁ImsPhone。mImsServiceReady标志取值由谁决定?这里先回头看在mImsIntentReceiver能否找到答案。

PhoneBase.javaprotected 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;        }    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

答案果然就在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();                }            }        }    };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

因此,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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

小结

google为IMS扩展了framework处理并向上提供了接口,而MTK实现了ims app(vendor目录),对接so库和rild的核心逻辑。

后续有空再分析ims业务的注册流程,还有volte的通话流程。

阅读全文
0 0
原创粉丝点击