您的位置:首页 > 运维架构 > 网站架构

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

2017-12-07 10:38 435 查看


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.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;
}
}
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的通话流程。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  IMS Phone