Android 4.4 Kitkat Phone工作流程浅析(三)__MO(去电)流程分析

来源:互联网 发布:淘宝上送的优酷会员 编辑:程序博客网 时间:2024/05/17 10:27
本文来自http://blog.csdn.net/yihongyuelan 转载请务必注明出处

本文代码以MTK平台Android 4.4为分析对象,与Google原生AOSP有些许差异,请读者知悉。

前置文章:

《Android 4.4 Kitkat Phone工作流程浅析(一)__概要和学习计划》

《Android 4.4 Kitkat Phone工作流程浅析(二)__UI分析》

        前面我们已经大致了解了 Android 4.4 Phone 大致差异以及整体结构,本文主要分析 Android 4.4 Phone 的去电流程。通话是手机最基本也是最终要的功能,而通话可以大致分为来电和去电,这也是对Phone模块熟悉必不可少的基本流程。

        本文主要以方法调用时序图以及关键代码作为分析,因芯片厂商差异所以代码与原生略有出入,各位看官取其所需即可,切不可生搬硬套。

        MTK在Android的原生的基础上添加了很多功能,比如VideoCall, 来电/去电归属地等等,这些功能是Android原生所不具有。MTK在加入这些功能的同时,为了方便后续移植使用了一套自己的架构即pluginManager ( Phone中使用ExtensionManager从PluginManager中获取实例,Contacts也使用同样的方式 )。什么是PluginManager呢?当我们需要增强Android原生APP的功能时,一般来讲我们可以直接去修改原生的代码添加我们想要的功能,但这样会导致Android原生代码混乱并可能降低执行效率等。MTK为解决这样的问题推出了Plugin架构,即使用类似插件的方式将新功能嵌入到Android原生代码中,但这也并不是说一点都不会修改Android原生代码。这样模块化的设计好处是显而易见的,PluginManager表示如图1:


图1

        这里为什么要提到Plugin呢?因为我们MTK平台Phone处理流程与原生的有所不同,MTK对拨号进行了一个预处理,我们姑且这么称呼吧,预处理主要目的是判断是否是Voice Mail, 是否是SIP Phone, 是否是Video Call等等,这些功能是MTK自己加入的,也就是说这里使用了plugin机制。

拨号时序图

        这里放上拨号时序图,具体信息就需要自己查看代码了,后面会简单提下我在看代码的过程中觉得一些重要的地方,因为图片太大后面会提供原图下载。时序图如图2:


图 2

        我们可以将图2分成四个部分:DialerPhoneCommonTeleServiceTelephony Framework。他们非别对应packages/apps/Dialer、packages/apps/PhoneCommon、packages/services/TeleService、framework/opt/telephony。实际上拨号操作会调用到RIL并使用AT指令发送给Modem,最终Modem与硬件交互后向基站发起通话请求,本文流程以APP-Framework为主。

拨号入口Dialer

        前面的文章我们已经提到 4.4 中的拨号界面不在附属于 Contacts 而是独立的Dialer应用,也就是把Contacts中Dialpad部分抽离了出来。拨号界面是DialtactsActivity,实际控件为DialpadFragment,点击拨号按钮触发DialpadFragment的onClick事件,并调用dialButtonPressed方法中,最终调用到ContactsCallOptionHandler中开始拨号预处理。整个过程比较简单,就不贴代码了。如图3:


图 3

拨号预处理PhoneCommon

        这里所说的拨号预处理是对于MTK平台来讲的,Android 原生没有这一块,直接从DialpadFragment使用StartAcitivty跳转到OutgongCallBroadcaster,我们主要看一下MTK对这一块做了什么。

        通过Dialer拨号我们可以知道,在Dialer的ContactsCallOptionHandler类中,调用doCallOptionHandle方法开启Phone的入口。代码如下:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public void doCallOptionHandle(Intent intent) {  
  2.       
  3.     //... ...省略部分代码,这里通过调用父类的doCallOptionHandle开始跳转到PhoneCommon中  
  4.     super.doCallOptionHandle(mActivityContext, DialerApplication.getInstance(), intent,  
  5.                              this, DialerApplication.getInstance().cellConnMgr,  
  6.                              telephony, SlotUtils.isGeminiEnabled(),  
  7.                              FeatureOption.MTK_GEMINI_3G_SWITCH);  
  8.   
  9. }  
看到CallOptionHandler中的doCallOptionHandle方法:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public void doCallOptionHandle(Context activityContext, Context applicationContext, Intent intent,  
  2.                                CallOptionBaseHandler.ICallOptionResultHandle resultHandler,  
  3.                                CellConnMgr cellConnMgr, ITelephony telephonyInterface,  
  4.                                boolean isMultipleSim, boolean is3GSwitchSupport) {  
  5.     ListIterator<CallOptionBaseHandler> iterator = mCallOptionHandlerList.listIterator();  
  6.     CallOptionBaseHandler previousHandler = iterator.next();  
  7.     while (iterator.hasNext()) {  
  8.         CallOptionBaseHandler currentHandler = (CallOptionBaseHandler)iterator.next();  
  9.         previousHandler.setSuccessor(currentHandler);  
  10.         previousHandler = currentHandler;  
  11.     }  
  12.   
  13.     Request request = new Request(activityContext, applicationContext, intent, resultHandler,  
  14.                                   cellConnMgr, telephonyInterface, isMultipleSim, is3GSwitchSupport,  
  15.                                   mCallOptionHandlerFactory);  
  16.     mCallOptionHandlerList.getFirst().handleRequest(request);  
  17. }  
按照常理,我们直接去跟踪handleRequest方法就好了,可是这里MTK做了一个链表的结构。我们先看到这里的mCallOptionHandlerList对象,需要知道第一个节点中存放的内容。mCallOptionHandlerList的赋值是在CallOptionHandler的构造方法中完成的,如下:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public CallOptionHandler(CallOptionHandlerFactory callOptionHandlerFactory) {  
  2.     mCallOptionHandlerFactory = callOptionHandlerFactory;  
  3.     mCallOptionHandlerList = new LinkedList<CallOptionBaseHandler>();  
  4.   
  5.     mCallOptionHandlerList.add(callOptionHandlerFactory.getFirstCallOptionHandler());  
  6.     mCallOptionHandlerList.add(callOptionHandlerFactory.getEmergencyCallOptionHandler());  
  7.     mCallOptionHandlerList.add(callOptionHandlerFactory.getInternetCallOptionHandler());  
  8.     mCallOptionHandlerList.add(callOptionHandlerFactory.getVideoCallOptionHandler());  
  9.     mCallOptionHandlerList.add(callOptionHandlerFactory.getSimSelectionCallOptionHandler());  
  10.     mCallOptionHandlerList.add(callOptionHandlerFactory.getSimStatusCallOptionHandler());  
  11.     mCallOptionHandlerList.add(callOptionHandlerFactory.getVoiceMailCallOptionHandler());  
  12.     mCallOptionHandlerList.add(callOptionHandlerFactory.getInternationalCallOptionHandler());  
  13.     mCallOptionHandlerList.add(callOptionHandlerFactory.getIpCallOptionHandler());  
  14.     mCallOptionHandlerList.add(callOptionHandlerFactory.getFinalCallOptionHandler());  
  15. }  
这里完成的链表的构造,但还是无法直接看出第一个节点内容是什么,因此我们需要继续查看调用CallOptionHandler构造方法的地方,并弄清楚传递的参数。经过查看我们可以知道在Dialer中的ContactsCallOptionHandler构造方法中使用super调用了父类构造方法,其父类就是CallOptionHandler。
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public ContactsCallOptionHandler(Context activityContext, CallOptionHandlerFactory callOptionHandlerFactory) {  
  2.     super(callOptionHandlerFactory);  
  3.     mActivityContext = activityContext;  
  4. }  
继续查看ContactsCallOptionHandler构造方法调用处。我们在Dialer中DialpadFragment的onCreate方法里看到了调用:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. mCallOptionHandler = new ContactsCallOptionHandler(getActivity(),  
  2.                 new ContactsCallOptionHandlerFactory());  
这里完成了真正的赋值,也就说CallOptionHandler中的mCallOptionHandlerList链表对象,使用了ContactsCallOptionHandlerFactory的对象进行了赋值。说白了就是:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. mCallOptionHandlerList.add(callOptionHandlerFactory.getFirstCallOptionHandler());  
  2. //等价于  
  3. mCallOptionHandlerList.add(new ContactsCallOptionHandlerFactory().getFirstCallOptionHandler());  
  4.   
  5.   
  6. mCallOptionHandlerList.getFirst().handleRequest(request);  
  7. //等价于  
  8. new ContactsCallOptionHandlerFactory().getFirstCallOptionHandler().handleRequest(request);  
ContactsCallOptionHandlerFactory类继承自CallOptionHandlerFactory,该类是一个抽象类,需要实现抽象方法createHandlerPrototype。ContactsCallOptionHandlerFactory本身并不具有getFirstCallOptionHandler()方法,而需要调用其父类的该方法:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public class ContactsCallOptionHandlerFactory extends CallOptionHandlerFactory {  
  2.     protected void createHandlerPrototype() {  
  3.         mInternetCallOptionHandler = new ContactsInternetCallOptionHandler();  
  4.         mVideoCallOptionHandler = new ContactsVideoCallOptionHandler();  
  5.         mInternationalCallOptionHandler = new ContactsInternationalCallOptionHandler();  
  6.         mSimSelectionCallOptionHandler = new ContactsSimSelectionCallOptionHandler();  
  7.         mSimStatusCallOptionHandler = new ContactsSimStatusCallOptionHandler();  
  8.         mIpCallOptionHandler = new ContactsIpCallOptionHandler();  
  9.         mVoiceMailCallOptionHandler = new ContactsVoiceMailCallOptionHandler();  
  10.         ExtensionManager.getInstance().getContactsCallOptionHandlerFactoryExtension().createHandlerPrototype(this);  
  11.     }  
  12. }  

        在实例化ContactsCallOptionHandlerFactory对象的时候会调用其父类构造方法即:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public abstract class CallOptionHandlerFactory {  
  2.   
  3.     protected CallOptionBaseHandler mFirstCallOptionHandler;  
  4.     protected CallOptionBaseHandler mEmergencyCallOptionHandler;  
  5.     protected CallOptionBaseHandler mInternetCallOptionHandler;  
  6.     protected CallOptionBaseHandler mVideoCallOptionHandler;  
  7.     protected CallOptionBaseHandler mInternationalCallOptionHandler;  
  8.     protected CallOptionBaseHandler mSimSelectionCallOptionHandler;  
  9.     protected CallOptionBaseHandler mSimStatusCallOptionHandler;  
  10.     protected CallOptionBaseHandler mIpCallOptionHandler;  
  11.     protected CallOptionBaseHandler mVoiceMailCallOptionHandler;  
  12.     protected CallOptionBaseHandler mFinalCallOptionHandler;  
  13.     //调用这里的构造方法  
  14.     public CallOptionHandlerFactory() {  
  15.         mFirstCallOptionHandler = new FirstCallOptionHandler();  
  16.         mEmergencyCallOptionHandler = new EmergencyCallOptionHandler();  
  17.         mFinalCallOptionHandler = new FinalCallOptionHandler();  
  18.         createHandlerPrototype();//这里完成部分初始化  
  19.     }  
  20.   
  21.     protected abstract void createHandlerPrototype();  
  22.   
  23.     public CallOptionBaseHandler getFirstCallOptionHandler() {  
  24.         return mFirstCallOptionHandler;  
  25.     }  
  26.   
  27.     public CallOptionBaseHandler getInternetCallOptionHandler() {  
  28.         return mInternetCallOptionHandler;  
  29.     }  
  30.   
  31.     //... ...省略  
  32. }  
这是典型的工厂模式,通过这里我们可以知道:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. mCallOptionHandlerList.getFirst().handleRequest(request);  
  2. //等价于  
  3. new ContactsCallOptionHandlerFactory().getFirstCallOptionHandler().handleRequest(request);  
  4. //等价于  
  5. mFirstCallOptionHandler.handleRequest(request);  
也就是说PhoneCommon的第一个handleRequest是在FirstCallOptionHandler中。代码如下:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. @Override  
  2. public void handleRequest(final Request request) {  
  3.     log("handleRequest()");  
  4.   
  5.     //If the call is an voicemail, we put an exact slot here if the voice call  
  6.     //setting isn't always ask. This will help to get the correct voice mail number.  
  7.     Intent intent = request.getIntent();  
  8.     Context ctx = request.getApplicationContext();  
  9.     if (Constants.VOICEMAIL_URI.equals(intent.getData().toString())) {  
  10.         final long defaultSim = Settings.System.getLong(ctx.getContentResolver(),  
  11.                 Settings.System.VOICE_CALL_SIM_SETTING, Settings.System.DEFAULT_SIM_NOT_SET);  
  12.         final SIMInfoWrapper simInfoWrapper = com.mediatek.phone.SIMInfoWrapper.getDefault();  
  13.         if (defaultSim > 0 && simInfoWrapper.getSlotIdBySimId((int)defaultSim) >= 0) {  
  14.             intent.putExtra("simId", simInfoWrapper.getSlotIdBySimId((int)defaultSim));  
  15.         }  
  16.     }  
  17.     if (null != mSuccessor) {  
  18.         mSuccessor.handleRequest(request);  
  19.     }  
  20. }  
根据MTK的注释我们大概知道FirstCallOptionHandler主要是为了voicemail做一些特殊的处理,即在intent中加入了simId字段。但我们这里是进行普通的拨号,因此不会执行voicemail相关代码,直接执行mSuccessor.handleRequest()方法。

        这里比较重要了,这个mSuccessor对象是什么呢?它的定义在抽象类CallOptionBaseHandler中,而FirstCallOptionHandler是CallOptionBaseHandler的子类:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. protected CallOptionBaseHandler mSuccessor;  
这里我们回到前面CallOptionHandler的doCallOptionHandle方法,注意到:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. ListIterator<CallOptionBaseHandler> iterator = mCallOptionHandlerList.listIterator();  
  2. CallOptionBaseHandler previousHandler = iterator.next();  
  3. while (iterator.hasNext()) {  
  4.     CallOptionBaseHandler currentHandler = (CallOptionBaseHandler)iterator.next();  
  5.     previousHandler.setSuccessor(currentHandler);//也就是说前一个对象的mSuccessor对象是当前的OptionHanderHandler  
  6.     previousHandler = currentHandler;  
  7. }  
这里建立了链表,那么FirstCallOptionHandler中的mSuccessor.handleRequest()方法自然跳转到EmergencyCallOptionHandler中,并依次执行下去。我们通过Log可以看出整个执行流程。
[plain] view plaincopy在CODE上查看代码片派生到我的代码片
  1. Line 6647: 03-11 16:17:37.721 D/FirstCallOptionHandler( 1944): handleRequest()  
  2. Line 6649: 03-11 16:17:37.721 D/EmergencyCallOptionHandler( 1944): handleRequest()  
  3. Line 6655: 03-11 16:17:37.721 D/InternetCallOptionHandler( 1944): handleRequest()  
  4. Line 6657: 03-11 16:17:37.721 D/VideoCallOptionHandler( 1944): handleRequest()  
  5. Line 6659: 03-11 16:17:37.721 D/VideoCallOptionHandler( 1944): handleRequest(), but not video  
  6. Line 6661: 03-11 16:17:37.721 D/SimSelectionCallOptionHandler( 1944): handleRequest()  
  7. Line 7721: 03-11 16:17:39.461 D/SimStatusCallOptionHandler( 1944): handleRequest(), slot = 0  
  8. Line 7735: 03-11 16:17:39.461 D/VoiceMailCallOptionHandler( 1944): handleRequest()  
  9. Line 7737: 03-11 16:17:39.461 D/InternationalCallOptionHandler( 1944): handleRequest()  
  10. Line 7797: 03-11 16:17:39.461 D/IpCallOptionHandler( 1944): handleRequest()  
  11. Line 7799: 03-11 16:17:39.461 D/FinalCallOptionHandler( 1944): handleRequest()  
也就是说整个拨号预处理过程分为10个阶段,分别为:

1. FirstCallOptionHandler

开始拨号预处理,判断呼叫号码是否属于voicemail,如果是则对intent进行一些处理,添加simId字段;

2. EmergencyCallOptionHandler

判断呼叫号码是否为紧急号码,如果是紧急号码则不再进行后续判断而直接开始拨号操作(跳转到OutgoingCallReceiver);

3. InternetCallOptionHandler

判断当前呼叫号码是否为网络拨号,即SIP Phone;

4. VideoCallOptionHandler

判断当前是否是进行的视屏拨号,即Video Call;

5. SimSelectionCallOptionHandler

判断当前使用哪一张SIM卡进行拨号。这一步会根据用户设置的默认SIM卡进行拨号,默认是弹出对话框,用户选择其中一张SIM卡进行拨号;

6. SimStatusCallOptionHandler

判断当前SIM卡状态是否允许拨号操作;

7. VoiceMailCallOptionHandler

判断当前呼叫号码是否属于voicemail,如果是则进行相关处理;

8. InternationalCallOptionHandler

判断呼叫号码是否符合当前国家ISO码;

9. IpCallOptionHandler

判断当前呼叫号码是否是IP呼叫(加拨17951);

10. FinalCallOptionHandler

会到Dialer中的ContactsCallOptionHandler中;

整个过程如图4:

图 4

以上就是拨号的号码预处理流程,这个预处理流程时序图如下:


图 5

TeleService服务处理

        在TeleService中还是会进行各种判断,这些判断有的是在PhoneCommon中做过的,但这是Android原生流程,MTK并没有去修改。比如期间还是有SIP Call和Emergency  Call的判断。

        经过前面的PhoneCommon之后,会使用以下方式发出广播:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public void onContinueCallProcess(Intent intent) {  
  2.     //清楚PhoneCommon过程中产生的dialog  
  3.     dismissDialogs();  
  4.     /** @} */  
  5.     intent.setAction(Constants.OUTGOING_CALL_RECEIVER);  
  6.     intent.setClassName(Constants.PHONE_PACKAGE, Constants.OUTGOING_CALL_RECEIVER);  
  7.     DialerApplication.getInstance().sendBroadcast(intent);  
  8. }  
这里就和原生Android有点区别了,Android原生是直接使用StartActivity的方式启动到OutgoingCallBroadcaster去,而这里是通过广播跳转到,TeleService/com/mediatek/phone/OutgoingCallReceiver中去。在原生 Android中是没有OutgoingCallReceiver.java的,它是OutgoingCallBroadcaster.java的内部类,这里被提取了出来。
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. @Override  
  2. public void onReceive(Context context, Intent intent) {  
  3.     if (Constants.OUTGOING_CALL_RECEIVER.equals(intent.getAction())) {  
  4.         Intent broadcastIntent = new Intent(Intent.ACTION_NEW_OUTGOING_CALL);  
  5.         String number = CallOptionUtils.getInitialNumber(context, intent);  
  6.         OutgoingCallBroadcaster.sendNewCallBroadcast(context, intent, number, falsethis);  
  7.         //... ...省略  
  8.     }  
  9. }  
这里调用OutgingCallBroadcaster的sendNewCallBroadcast方法继续拨号流程:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public static void sendNewCallBroadcast(Context context, Intent intent, String number,  
  2.                                         boolean callNow, BroadcastReceiver receiver) {  
  3.     //... ...省略 这里指定了接收的receiver,也就是前面提到的OutgoingCallReceiver  
  4.     context.sendOrderedBroadcastAsUser(broadcastIntent, UserHandle.OWNER,  
  5.             PERMISSION, receiver,  
  6.             null,  // scheduler  
  7.             Activity.RESULT_OK,  // initialCode  
  8.             number,  // initialData: initial value for the result data  
  9.             null);  // initialExtras  
  10. }  
看到这里我也很纳闷,为什么要这样转一圈呢?直接跳转过去不可以?这个要问就只能问写这块代码的人了。我发现这些代码从MTK 2.3 到 4.2 在结构上都没怎么变化,我猜测是因为之前的架构是这样做的,后面只是移植并没有去优化完善,除非有bug采取解决,否则就只是拿来使用了。

        这里通过制定receiver又跳转到了OutgoingCallReceiver的onReceive方法中,根据Action:Intent.ACTION_NEW_OUTGOING_CALL执行代码如下:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. @Override  
  2. public void onReceive(Context context, Intent intent) {  
  3.     if (Constants.OUTGOING_CALL_RECEIVER.equals(intent.getAction())) {  
  4.         //... ...省略 第一次执行这里  
  5.     } else if (Intent.ACTION_NEW_OUTGOING_CALL.equals(intent.getAction())) {  
  6.         //... ...省略 判断是否是SIP Call  
  7.         if ((PhoneNumberUtils.isUriNumber(number) && intent.getIntExtra(Constants.EXTRA_SLOT_ID, -1) == -1)  
  8.                 || Constants.SCHEME_SIP.equals(uri.getScheme())) {  
  9. //... ...省略 如果是SIP Call则执行  
  10.             startSipCallOptionHandler(context, newIntent);  
  11.         } else {  
  12. //... ...省略 经过前面处理之后,开始往framework传递  
  13.             PhoneGlobals.getInstance().callController.placeCall(newIntent);  
  14.         }  
  15.     }  
  16. }  
跳转到CallController中继续执行,根据拨号类型( 这里所说的类型是双卡拨号,视屏拨号 ),再跳转到PhoneUtils中的placeCallGemini方法中,在该方法中也会调用startGetCallerInfo()方法获取呼叫号码的信息,用于显示在CallCard上。

        TeleService中Call处理部分,实际上主要是后台逻辑处理,Android 4.4 Phone最重要的特点就是将显示和逻辑分离。这块与Android 4.2改动并不大,只是从原来的Phone中分离了出来。

TeleService执行时序图如下:

图 6

Framework Telephony处理拨号请求

        这里的调用和参数传递也比较多,有几个关键点需要提一下。当我们跳转到CallManager的dial方法后,会执行到以下代码获取Connection:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. result = basePhone.dial(dialString);  
basePhone是Phone对象,而Phone是一个接口类,而且这里是通过参数传递过来的。我们在CallController的placeCallInternal()方法中可以看到以下代码:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. phone = PhoneUtils.pickPhoneBasedOnNumber(mCM, scheme, number, sipPhoneUri);  
继续查看pickPhoneBasedOnNumber方法:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public static Phone pickPhoneBasedOnNumber(CallManager cm,  
  2.         String scheme, String number, String primarySipUri) {  
  3.     if (primarySipUri != null) {  
  4.         Phone phone = getSipPhoneFromUri(cm, primarySipUri);  
  5.         if (phone != nullreturn phone;  
  6.     }  
  7.     return CallManagerWrapper.getDefaultPhone();//不是SIP Call  
  8. }  
继续查看CallManagerWrapper中的getDefaultPhone方法:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public static Phone getDefaultPhone() {  
  2.     Phone phone = null;  
  3.     if (GeminiUtils.isGeminiSupport()) {//是否支持双卡  
  4.         phone = ((GeminiPhone) MTKCallManager.getInstance().getDefaultPhoneGemini());  
  5.     } else {  
  6.         phone = CallManager.getInstance().getDefaultPhone();  
  7.     }  
  8.     return phone;  
  9. }  


        因为这里是MTK GSM/WCDMA制式的手机,因此是支持双SIM卡的。双SIM卡支持是Android原生没有的,MTK自己做了这一块,但却把相关方法实现封装到了jar包中,并进行混淆(这一点高通就比较厚道,直接开放源代码)。这里我们需要查看MTKCallManager中的代码,直接搜索是找不到的。我们来看一下MTKCallManager相关架构图,如下:

图 7

MTK加入了这个所谓MTKCallManager主要目的是用于管理双卡这块,关于双卡分析后面再做。

虽然MTK将Gemini相关代码封装到了jar包中,但我们依然可以将其反解进行查看,在该路径下找到gemini所使用的jar包:

SourceCode/vendor/mediatek/banyan_addon_x86/artifacts/out/target/common/obj/JAVA_LIBRARIES/static_gemini_intermediates/classes.jar

banyan_addon_x86是MTK的模拟器,我们找到其中MTKCallManager的getDefaultPhoneGemini如下:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public Phone getDefaultPhoneGemini()  
  2. {  
  3.   return this.U;  
  4. }  
这里的U是Phone对象,我们可以简单的这样理解MTK的双卡改动,将单卡流程复制一遍,然后弄一个MTKCallManager来管理总管理。

那么这里的Phone是如何赋值的呢,可以看到有一个registerPhoneGemini的方法:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public void registerPhoneGemini(Phone paramPhone){  
  2.   this.U = paramPhone;  
  3.   //... ...省略 }  
那么这里的registerPhoneGemini()是什么时候调用的呢?我们看到TeleService的PhoneGlobals.java中onCreate方法:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1.    public void onCreate() {  
  2.     //... ...省略  
  3.        if (phone == null) {  
  4.            PhoneFactory.makeDefaultPhones(this);  
  5.            // Get the default phone  
  6.            phone = PhoneFactory.getDefaultPhone();  
  7.            //... ...省略  
  8.            registerPhone();  
  9.            //... ...省略  
  10.        }  
  11. //... ...省略  
  12.   }  
这里为什么要找到PhoneGlobals中呢?这要说道Phone的启动流程了,后面再介绍吧。在第一次启动时phone == null,因此就会执行其中的makeDefaultPhones方法:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public static void makeDefaultPhones(Context context) {  
  2. 否支持双卡  
  3.     if (FeatureOption.MTK_GEMINI_SUPPORT == true){  
  4.         SystemProperties.set(Phone.GEMINI_DEFAULT_SIM_MODE, String.valueOf(RILConstants.NETWORK_MODE_GEMINI));  
  5.         MTKPhoneFactory.makeDefaultPhone(context, RILConstants.NETWORK_MODE_GEMINI);  
  6.     }else{  
  7.         SystemProperties.set(Phone.GEMINI_DEFAULT_SIM_MODE, String.valueOf(RILConstants.NETWORK_MODE_WCDMA_PREF));  
  8.         MTKPhoneFactory.makeDefaultPhone(context, RILConstants.NETWORK_MODE_WCDMA_PREF);  
  9.     }  
  10.     //... ...省略  
  11. }  
接下来找到MTKPhoneFactory中的makeDefalutPhone方法:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1.   public static void makeDefaultPhone(Context paramContext, int paramInt)  
  2.   {  
  3.     //如果是Gemini那么S=RILConstants.NETWORK_MODE_GEMINI  
  4.     //如果不是Gemini那么S=RILConstants.NETWORK_MODE_WCDMA_PREF  
  5.     S = paramInt;  
  6.     makeDefaultPhone(paramContext);  
  7.   }  
  8.   
  9.   public static void makeDefaultPhone(Context paramContext) {  
  10.     synchronized (Phone.class) {  
  11.       if (!M) {  
  12.         //... ...省略 创建本地socket服务端  
  13.         new LocalServerSocket("com.android.internal.telephony");  
  14.         N = new DefaultPhoneNotifier();  
  15.   
  16.         //... ...省略 获取Phone Type  
  17.         int i1 = getPhoneType(j);         
  18.         if (i1 == 1) { //if phoneType == PhoneConstants.PHONE_TYPE_GSM  
  19.           I = new RIL(paramContext, localInterruptedException1, k, 0);  
  20.           UiccController.make(paramContext, I);  
  21.           H = new PhoneProxy(new GSMPhone(paramContext, I, N));  
  22.           Rlog.i("PHONE""Creating GSMPhone");  
  23.         } else if (i1 == 2) { //if phoneType == PhoneConstants.PHONE_TYPE_CDMA  
  24.           I = new RIL(paramContext, localInterruptedException1, k, 0);  
  25.           UiccController.make(paramContext, I);  
  26.           H = new PhoneProxy(new CDMAPhone(paramContext, I, N));  
  27.           Rlog.i("PHONE""Creating CDMAPhone");  
  28.         } else if (i1 == 4) { //if phoneType == PhoneConstants.PHONE_TYPE_GEMINI  
  29.           //这里DefaultPhoneNotifier的参数是指定SIM卡id  
  30.           //... ...省略            
  31.           //GEMINI_SIM_NUM = 2  
  32.           int[] arrayOfInt = new int[PhoneConstants.GEMINI_SIM_NUM];  
  33.           //... ...省略  
  34.           //... ...arrayOfInt[0]和arrayOfInt[1]均=1  
  35.           //... ...获取RILJ对象这里的RIL构造方法最后一个参数是SimId  
  36.           //... ...int k = CdmaSubscriptionSourceManager.getDefault(paramContext);  
  37.           I = new RIL(paramContext, arrayOfInt[0], k, 0);  
  38.           J = new RIL(paramContext, arrayOfInt[1], k, 1);  
  39.             
  40.           //... ...省略 初始化GSMPhone数组            
  41.           GSMPhone[] arrayOfGSMPhone = new GSMPhone[PhoneConstants.GEMINI_SIM_NUM];  
  42.             
  43.           arrayOfGSMPhone[0] = new GSMPhone(paramContext, I, N, 0);  
  44.             
  45.           arrayOfGSMPhone[1] = new GSMPhone(paramContext, J, O, 1);  
  46.             
  47.           if (PhoneConstants.GEMINI_SIM_NUM == 2) {  
  48.               //这里的H实际上为GeminiPhone对象,而GeminiPhone extends Handler implements Phone  
  49.               H = new GeminiPhone(new PhoneProxy(arrayOfGSMPhone[0]), new PhoneProxy(arrayOfGSMPhone[1]), i2);  
  50.           }  
  51.           //... ...省略  
  52.         }  
  53.        }  
  54.    }  
  55. }  
这里的H 实际上是GeminiPhone对象,而GeminiPhone extends Handler implement Phone,因此H实际上在这里完成了实例化,GeminiPhone负责双卡管理,对于GeminiPhone这里就再去细究了。通过代码可以看到最终我们是通过PhoneProxy来获取到的Phone对象,而这里的Phone对象实际上为GSMPhone,arrayOfGSMPhone数组可以看到。这里完成H对象(Phone对象)的赋值后,我们可以看到PhoneGlobals的onCreate中:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. phone = PhoneFactory.getDefaultPhone();  
  2. registerPhone();  
通过getDefalutPhone()方法获取phone对象:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public static Phone getDefaultPhone() {  
  2. turn MTKPhoneFactory.getDefaultPhone();  
  3. }  
以及:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public static Phone getDefaultPhone()  
  2. {  
  3.   return H;  
  4. }  
最终调用到registerPhone方法:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. private void registerPhone() {  
  2.     mCM = CallManager.getInstance();  
  3.     if (GeminiUtils.isGeminiSupport()) {  
  4.         mCMGemini = MTKCallManager.getInstance();  
  5.  //mCMGemini是MTKCallManager对象,这里完成了phone注册  
  6.         mCMGemini.registerPhoneGemini(phone);  
  7.     } else {  
  8.         mCM.registerPhone(phone);  
  9.     }  
  10. }  
回过头来,我们终于找到了
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. result = basePhone.dial(dialString);  
中的basePhone,实际应为GSMPhone自然继续跳转拨号。后续流程就是通过framework通知到RIL层,RIL层再使用AT指令发送到modem端最终完成拨号动作。

整个时序图如下:

图 8

总结

        整个MO流程看起来很复杂,但我们可以简单的归结为四个步骤:

        1. 拨号处理;

        2. 号码预处理;

        3. TeleService后台处理;

        4. framework telephony处理;

        如果从严格意义上来讲的话,还应该加上RIL处理和modem处理,但这两块并不是本文的侧重点,后续有机会在去分析研究。

对于这一块的学习,个人觉得难点主要在于对通信协议不熟悉,很多地方这么设计是依据协议和设计模式来的。关于MTK双卡部分,如果我们仔细阅读代码后会发现,其设计框架还是比较容易理解的。就好比你有两辆车,你需一个管家根据实际情况给你分配不同的车来使用。

        对于Android 4.4 的拨号流程来讲,实际上与4.2的差别并不是想象中的那么大,改变最大还是UI与逻辑的拆分,这一点在上一篇文章《Android 4.4 Kitkat Phone工作流程浅析(二)__UI结构分析》 中有分析到,拨号流程并没有太大的改变。

        文中对于basePhone的定位和分析对于理解MTK双卡架构还是有些许帮助的,后面会分析MT(来电)流程,敬请期待。

        对于使用原生或者高通代码的童鞋可以看看这篇文章,这位童鞋的分析还是很到位的,心急的可以直接跳到最后去看框架图。

        最后给出本文所使用的图片资源以及MTK_Android_4.4_Gemini.jar下载地址:免积分下载

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 移动宽带网络不稳定怎么办 股票帐号被锁定怎么办 电脑帐号锁定了怎么办 云校家帐号被锁定怎么办 qq音乐停止运行怎么办 做事效率低怎么办教案 孩子做事效率低怎么办 百度搜不到答案怎么办 学乐云账号忘了怎么办 wps云空间不足怎么办 超星密码忘了怎么办 百度钱包忘记密码怎么办 宝宝吃了粉笔怎么办 粉笔灰进眼睛怎么办 讲公开课紧张怎么办 课堂派考勤旷课怎么办 2018qq音乐付费怎么办 不满一个月社保怎么办 试用期未买社保怎么办 小视频转发黑屏怎么办 听歌要钱的怎么办 手机歌曲要付费怎么办 安装包已损坏怎么办 方舟 安装包损坏怎么办 安装包已删除怎么办 超大附件过期了怎么办 邮箱被黑客盯上怎么办 云闪付安全问题忘记了怎么办 不知道网易账号怎么办 登录过程初始化失败怎么办 登录进程初始化失败怎么办 网易邮箱地址忘了怎么办 电脑电源短路了怎么办 电脑电源有问题怎么办 手机账号忘了怎么办 简历周五发了怎么办 网易邮箱被注销怎么办 foxmail接收密码忘记怎么办 招才猫企业邮箱认证没有怎么办 管理员账号被删除怎么办 我想办个信用卡怎么办