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的判断即可。
MTK IMS框架简析(1)——代码架构及模块初始化_第1张图片

上图看到架构基本与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/并由它来实现具体的业务。

MTK IMS框架简析(1)——代码架构及模块初始化_第2张图片

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/)

MTK IMS框架简析(1)——代码架构及模块初始化_第3张图片

framework中相关公共类和aidl定义

/frameworks/base/telephony/java/com/android/ims
frameworks/base…/ims下定义了一些可以公用的类,都属于特定数据的封装,基本上都继承了aidl stub跨进程无压力。

internal包下还定义了一系列aidl文件,具体实现都在/vendor/mediatek/proprietary/packages/services/Ims/中,为其提供访问入口。
MTK IMS框架简析(1)——代码架构及模块初始化_第4张图片

3. 模块的初始化

以上模块在开机后即开始初始化过程,下面来看下它们如何开始初始化。

mtk ims应用初始化

/vendor/mediatek/…/services/Ims/ 在AndroidManifest中定义了application的persistent为true,因此ims app开机即自动加载:

"ImsApp" 
             android:persistent="true">
        ...

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的通话流程。

你可能感兴趣的:(Android,Telephony,框架源码分析)