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

来源:互联网 发布:人工智能相关的电影 编辑:程序博客网 时间:2024/04/20 10:57
本文来自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原生代码。

        这里为什么要提到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 plain copy
 在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 plain copy
 在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 plain copy
 在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 plain copy
 在CODE上查看代码片派生到我的代码片
  1. public ContactsCallOptionHandler(Context activityContext, CallOptionHandlerFactory callOptionHandlerFactory) {  
  2.     super(callOptionHandlerFactory);  
  3.     mActivityContext = activityContext;  
  4. }  
继续查看ContactsCallOptionHandler构造方法调用处。我们在Dialer中DialpadFragment的onCreate方法里看到了调用:
[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. mCallOptionHandler = new ContactsCallOptionHandler(getActivity(),  
  2.                 new ContactsCallOptionHandlerFactory());  
这里完成了真正的赋值,也就说CallOptionHandler中的mCallOptionHandlerList链表对象,使用了ContactsCallOptionHandlerFactory的对象进行了赋值。说白了就是:
[java] view plain copy
 在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 plain copy
 在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 plain copy
 在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 plain copy
 在CODE上查看代码片派生到我的代码片
  1. mCallOptionHandlerList.getFirst().handleRequest(request);  
  2. //等价于  
  3. new ContactsCallOptionHandlerFactory().getFirstCallOptionHandler().handleRequest(request);  
  4. //等价于  
  5. mFirstCallOptionHandler.handleRequest(request);  
也就是说PhoneCommon的第一个handleRequest是在FirstCallOptionHandler中。代码如下:
[java] view plain copy
 在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 plain copy
 在CODE上查看代码片派生到我的代码片
  1. protected CallOptionBaseHandler mSuccessor;  
这里我们回到前面CallOptionHandler的doCallOptionHandle方法,注意到:
[java] view plain copy
 在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 plain copy
 在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 plain copy
 在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 plain copy
 在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 plain copy
 在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 plain copy
 在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 plain copy
 在CODE上查看代码片派生到我的代码片
  1. result = basePhone.dial(dialString);  
basePhone是Phone对象,而Phone是一个接口类,而且这里是通过参数传递过来的。我们在CallController的placeCallInternal()方法中可以看到以下代码:
[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. phone = PhoneUtils.pickPhoneBasedOnNumber(mCM, scheme, number, sipPhoneUri);  
继续查看pickPhoneBasedOnNumber方法:
[java] view plain copy
 在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 plain copy
 在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. }  

        因为这里是GSM/WCDMA支持双SIM卡的手机,而双SIM卡支持是Android原生没有的,MTK自己做了这一块,但却把相关方法实现封装到了jar包中,并进行混淆(这一点高通就比较厚道,直接开放源代码)。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 plain copy
 在CODE上查看代码片派生到我的代码片
  1. public Phone getDefaultPhoneGemini()  
  2. {  
  3.   return this.U;  
  4. }  
这里的U是Phone对象,我们可以简单的这样理解MTK的双卡改动,将单卡流程复制一遍,然后弄一个MTKCallManager来管理总管理。

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

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. public void registerPhoneGemini(Phone paramPhone){  
  2.   this.U = paramPhone;  
  3.   //... ...省略 }  
那么这里的registerPhoneGemini()是什么时候调用的呢?我们看到TeleService的PhoneGlobals.java中onCreate方法:
[java] view plain copy
 在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 plain copy
 在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 plain copy
 在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 plain copy
 在CODE上查看代码片派生到我的代码片
  1. phone = PhoneFactory.getDefaultPhone();  
  2. registerPhone();  
通过getDefalutPhone()方法获取phone对象:
[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. public static Phone getDefaultPhone() {  
  2. turn MTKPhoneFactory.getDefaultPhone();  
  3. }  
以及:
[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. public static Phone getDefaultPhone()  
  2. {  
  3.   return H;  
  4. }  
最终调用到registerPhone方法:
[java] view plain copy
 在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 plain copy
 在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
原创粉丝点击