求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Modeler   Code  
会员   
 
  
 
 
     
   
分享到
(二)Android 4.4 Kitkat Phone工作流程浅析
 
作者 yihongyuelan的博客,火龙果软件    发布于 2014-04-30
 

(三)__MO(去电)流程分析

前面我们已经大致了解了 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分成四个部分:Dialer,PhoneCommon,TeleService,Telephony 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的入口。代码如下:

    public void doCallOptionHandle(Intent intent) {

//... ...省略部分代码,这里通过调用父类的doCallOptionHandle开始跳转到PhoneCommon中
super.doCallOptionHandle(mActivityContext, DialerApplication.getInstance(), intent,
this, DialerApplication.getInstance().cellConnMgr,
telephony, SlotUtils.isGeminiEnabled(),
FeatureOption.MTK_GEMINI_3G_SWITCH);
}

看到CallOptionHandler中的doCallOptionHandle方法:

    public void doCallOptionHandle(Context activityContext, Context applicationContext, Intent intent,
CallOptionBaseHandler.ICallOptionResultHandle resultHandler,
CellConnMgr cellConnMgr, ITelephony telephonyInterface,
boolean isMultipleSim, boolean is3GSwitchSupport) {
ListIterator<CallOptionBaseHandler> iterator = mCallOptionHandlerList.listIterator();
CallOptionBaseHandler previousHandler = iterator.next();
while (iterator.hasNext()) {
CallOptionBaseHandler currentHandler = (CallOptionBaseHandler)iterator.next();
previousHandler.setSuccessor(currentHandler);
previousHandler = currentHandler;
}
Request request = new Request(activityContext, applicationContext, intent, resultHandler,
cellConnMgr, telephonyInterface, isMultipleSim, is3GSwitchSupport,
mCallOptionHandlerFactory);
mCallOptionHandlerList.getFirst().handleRequest(request);
}

按照常理,我们直接去跟踪handleRequest方法就好了,可是这里MTK做了一个链表的结构。我们先看到这里的mCallOptionHandlerList对象,需要知道第一个节点中存放的内容。mCallOptionHandlerList的赋值是在CallOptionHandler的构造方法中完成的,如下:

    public CallOptionHandler(CallOptionHandlerFactory callOptionHandlerFactory) {
mCallOptionHandlerFactory = callOptionHandlerFactory;
mCallOptionHandlerList = new LinkedList<CallOptionBaseHandler>();
mCallOptionHandlerList.add(callOptionHandlerFactory.getFirstCallOptionHandler());
mCallOptionHandlerList.add(callOptionHandlerFactory.getEmergencyCallOptionHandler());
mCallOptionHandlerList.add(callOptionHandlerFactory.getInternetCallOptionHandler());
mCallOptionHandlerList.add(callOptionHandlerFactory.getVideoCallOptionHandler());
mCallOptionHandlerList.add(callOptionHandlerFactory.getSimSelectionCallOptionHandler());
mCallOptionHandlerList.add(callOptionHandlerFactory.getSimStatusCallOptionHandler());
mCallOptionHandlerList.add(callOptionHandlerFactory.getVoiceMailCallOptionHandler());
mCallOptionHandlerList.add(callOptionHandlerFactory.getInternationalCallOptionHandler());
mCallOptionHandlerList.add(callOptionHandlerFactory.getIpCallOptionHandler());
mCallOptionHandlerList.add(callOptionHandlerFactory.getFinalCallOptionHandler());
}

这里完成的链表的构造,但还是无法直接看出第一个节点内容是什么,因此我们需要继续查看调用CallOptionHandler构造方法的地方,并弄清楚传递的参数。经过查看我们可以知道在Dialer中的ContactsCallOptionHandler构造方法中使用super调用了父类构造方法,其父类就是CallOptionHandler。

    public ContactsCallOptionHandler(Context activityContext, CallOptionHandlerFactory callOptionHandlerFactory) {
super(callOptionHandlerFactory);
mActivityContext = activityContext;
}

继续查看ContactsCallOptionHandler构造方法调用处。我们在Dialer中DialpadFragment的onCreate方法里看到了调用:

mCallOptionHandler = new ContactsCallOptionHandler(getActivity(),
new ContactsCallOptionHandlerFactory());

这里完成了真正的赋值,也就说CallOptionHandler中的mCallOptionHandlerList链表对象,使用了ContactsCallOptionHandlerFactory的对象进行了赋值。说白了就是:

mCallOptionHandlerList.add(callOptionHandlerFactory.getFirstCallOptionHandler());
//等价于
mCallOptionHandlerList.add(new ContactsCallOptionHandlerFactory().getFirstCallOptionHandler()); mCallOptionHandlerList.getFirst().handleRequest(request);
//等价于
new ContactsCallOptionHandlerFactory().getFirstCallOptionHandler().handleRequest(request);

ContactsCallOptionHandlerFactory类继承自CallOptionHandlerFactory,该类是一个抽象类,需要实现抽象方法createHandlerPrototype。ContactsCallOptionHandlerFactory本身并不具有getFirstCallOptionHandler()方法,而需要调用其父类的该方法:

public class ContactsCallOptionHandlerFactory extends CallOptionHandlerFactory {
protected void createHandlerPrototype() {
mInternetCallOptionHandler = new ContactsInternetCallOptionHandler();
mVideoCallOptionHandler = new ContactsVideoCallOptionHandler();
mInternationalCallOptionHandler = new ContactsInternationalCallOptionHandler();
mSimSelectionCallOptionHandler = new ContactsSimSelectionCallOptionHandler();
mSimStatusCallOptionHandler = new ContactsSimStatusCallOptionHandler();
mIpCallOptionHandler = new ContactsIpCallOptionHandler();
mVoiceMailCallOptionHandler = new ContactsVoiceMailCallOptionHandler();
ExtensionManager.getInstance().getContactsCallOptionHandlerFactoryExtension().createHandlerPrototype(this);
}
}

在实例化ContactsCallOptionHandlerFactory对象的时候会调用其父类构造方法即:

public abstract class CallOptionHandlerFactory {
protected CallOptionBaseHandler mFirstCallOptionHandler;
protected CallOptionBaseHandler mEmergencyCallOptionHandler;
protected CallOptionBaseHandler mInternetCallOptionHandler;
protected CallOptionBaseHandler mVideoCallOptionHandler;
protected CallOptionBaseHandler mInternationalCallOptionHandler;
protected CallOptionBaseHandler mSimSelectionCallOptionHandler;
protected CallOptionBaseHandler mSimStatusCallOptionHandler;
protected CallOptionBaseHandler mIpCallOptionHandler;
protected CallOptionBaseHandler mVoiceMailCallOptionHandler;
protected CallOptionBaseHandler mFinalCallOptionHandler;
//调用这里的构造方法
public CallOptionHandlerFactory() {
mFirstCallOptionHandler = new FirstCallOptionHandler();
mEmergencyCallOptionHandler = new EmergencyCallOptionHandler();
mFinalCallOptionHandler = new FinalCallOptionHandler();
createHandlerPrototype();//这里完成部分初始化
}
protected abstract void createHandlerPrototype();
public CallOptionBaseHandler getFirstCallOptionHandler() {
return mFirstCallOptionHandler;
}
public CallOptionBaseHandler getInternetCallOptionHandler() {
return mInternetCallOptionHandler;
}
//... ...省略
}

这是典型的工厂模式,通过这里我们可以知道:

mCallOptionHandlerList.getFirst().handleRequest(request);
//等价于
new ContactsCallOptionHandlerFactory().getFirstCallOptionHandler().handleRequest(request);
//等价于
mFirstCallOptionHandler.handleRequest(request);

也就是说PhoneCommon的第一个handleRequest是在FirstCallOptionHandler中。代码如下:

    @Override
public void handleRequest(final Request request) {
log("handleRequest()");
//If the call is an voicemail, we put an exact slot here if the voice call
//setting isn't always ask. This will help to get the correct voice mail number.
Intent intent = request.getIntent();
Context ctx = request.getApplicationContext();
if (Constants.VOICEMAIL_URI.equals(intent.getData().toString())) {
final long defaultSim = Settings.System.getLong(ctx.getContentResolver(),
Settings.System.VOICE_CALL_SIM_SETTING, Settings.System.DEFAULT_SIM_NOT_SET);
final SIMInfoWrapper simInfoWrapper = com.mediatek.phone.SIMInfoWrapper.getDefault();
if (defaultSim > 0 && simInfoWrapper.getSlotIdBySimId((int)defaultSim) >= 0) {
intent.putExtra("simId", simInfoWrapper.getSlotIdBySimId((int)defaultSim));
}
}
if (null != mSuccessor) {
mSuccessor.handleRequest(request);
}
}

根据MTK的注释我们大概知道FirstCallOptionHandler主要是为了voicemail做一些特殊的处理,即在intent中加入了simId字段。但我们这里是进行普通的拨号,因此不会执行voicemail相关代码,直接执行mSuccessor.handleRequest()方法。
这里比较重要了,这个mSuccessor对象是什么呢?它的定义在抽象类CallOptionBaseHandler中,而FirstCallOptionHandler是CallOptionBaseHandler的子类:

    protected CallOptionBaseHandler mSuccessor;

这里我们回到前面CallOptionHandler的doCallOptionHandle方法,注意到:

        ListIterator<CallOptionBaseHandler> iterator = mCallOptionHandlerList.listIterator();
CallOptionBaseHandler previousHandler = iterator.next();
while (iterator.hasNext()) {
CallOptionBaseHandler currentHandler = (CallOptionBaseHandler)iterator.next();
previousHandler.setSuccessor(currentHandler);//也就是说前一个对象的mSuccessor对象是当前的OptionHanderHandler
previousHandler = currentHandler;
}

这里建立了链表,那么FirstCallOptionHandler中的mSuccessor.handleRequest()方法自然跳转到EmergencyCallOptionHandler中,并依次执行下去。我们通过Log可以看出整个执行流程。

Line 6647: 03-11 16:17:37.721 D/FirstCallOptionHandler( 1944): handleRequest()
Line 6649: 03-11 16:17:37.721 D/EmergencyCallOptionHandler( 1944): handleRequest()
Line 6655: 03-11 16:17:37.721 D/InternetCallOptionHandler( 1944): handleRequest()
Line 6657: 03-11 16:17:37.721 D/VideoCallOptionHandler( 1944): handleRequest()
Line 6659: 03-11 16:17:37.721 D/VideoCallOptionHandler( 1944): handleRequest(), but not video
Line 6661: 03-11 16:17:37.721 D/SimSelectionCallOptionHandler( 1944): handleRequest()
Line 7721: 03-11 16:17:39.461 D/SimStatusCallOptionHandler( 1944): handleRequest(), slot = 0
Line 7735: 03-11 16:17:39.461 D/VoiceMailCallOptionHandler( 1944): handleRequest()
Line 7737: 03-11 16:17:39.461 D/InternationalCallOptionHandler( 1944): handleRequest()
Line 7797: 03-11 16:17:39.461 D/IpCallOptionHandler( 1944): handleRequest()
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之后,会使用以下方式发出广播:

    public void onContinueCallProcess(Intent intent) {
//清楚PhoneCommon过程中产生的dialog
dismissDialogs();
/** @} */
intent.setAction(Constants.OUTGOING_CALL_RECEIVER);
intent.setClassName(Constants.PHONE_PACKAGE, Constants.OUTGOING_CALL_RECEIVER);
DialerApplication.getInstance().sendBroadcast(intent);
}

这里就和原生Android有点区别了,Android原生是直接使用StartActivity的方式启动到OutgoingCallBroadcaster去,而这里是通过广播跳转到,TeleService/com/mediatek/phone/OutgoingCallReceiver中去。在原生 Android中是没有OutgoingCallReceiver.java的,它是OutgoingCallBroadcaster.java的内部类,这里被提取了出来。

    @Override
public void onReceive(Context context, Intent intent) {
if (Constants.OUTGOING_CALL_RECEIVER.equals(intent.getAction())) {
Intent broadcastIntent = new Intent(Intent.ACTION_NEW_OUTGOING_CALL);
String number = CallOptionUtils.getInitialNumber(context, intent);
OutgoingCallBroadcaster.sendNewCallBroadcast(context, intent, number, false, this);
//... ...省略
}
}

这里调用OutgingCallBroadcaster的sendNewCallBroadcast方法继续拨号流程:

public static void sendNewCallBroadcast(Context context, Intent intent, String number,  
boolean callNow, BroadcastReceiver receiver) {
//... ...省略 这里指定了接收的receiver,也就是前面提到的OutgoingCallReceiver
context.sendOrderedBroadcastAsUser(broadcastIntent, UserHandle.OWNER,
PERMISSION, receiver,
null, // scheduler
Activity.RESULT_OK, // initialCode
number, // initialData: initial value for the result data
null); // initialExtras
}

看到这里我也很纳闷,为什么要这样转一圈呢?直接跳转过去不可以?这个要问就只能问写这块代码的人了。我发现这些代码从MTK 2.3 到 4.2 在结构上都没怎么变化,我猜测是因为之前的架构是这样做的,后面只是移植并没有去优化完善,除非有bug采取解决,否则就只是拿来使用了。

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

@Override  
public void onReceive(Context context, Intent intent) {
if (Constants.OUTGOING_CALL_RECEIVER.equals(intent.getAction())) {
//... ...省略 第一次执行这里
} else if (Intent.ACTION_NEW_OUTGOING_CALL.equals(intent.getAction())) {
//... ...省略 判断是否是SIP Call
if ((PhoneNumberUtils.isUriNumber(number) && intent.getIntExtra(Constants.EXTRA_SLOT_ID, -1) == -1)
|| Constants.SCHEME_SIP.equals(uri.getScheme())) {
//... ...省略 如果是SIP Call则执行
startSipCallOptionHandler(context, newIntent);
} else {
//... ...省略 经过前面处理之后,开始往framework传递
PhoneGlobals.getInstance().callController.placeCall(newIntent);
}
}
}

跳转到CallController中继续执行,根据拨号类型( 这里所说的类型是双卡拨号,视屏拨号 ),再跳转到PhoneUtils中的placeCallGemini方法中,在该方法中也会调用startGetCallerInfo()方法获取呼叫号码的信息,用于显示在CallCard上。
TeleService中Call处理部分,实际上主要是后台逻辑处理,Android 4.4 Phone最重要的特点就是将显示和逻辑分离。这块与Android 4.2改动并不大,只是从原来的Phone中分离了出来。

TeleService执行时序图如下:

图 6

Framework Telephony处理拨号请求

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

result = basePhone.dial(dialString);  

basePhone是Phone对象,而Phone是一个接口类,而且这里是通过参数传递过来的。我们在CallController的placeCallInternal()方法中可以看到以下代码:

phone = PhoneUtils.pickPhoneBasedOnNumber(mCM, scheme, number, sipPhoneUri);  

继续查看pickPhoneBasedOnNumber方法:

public static Phone pickPhoneBasedOnNumber(CallManager cm,  
String scheme, String number, String primarySipUri) {
if (primarySipUri != null) {
Phone phone = getSipPhoneFromUri(cm, primarySipUri);
if (phone != null) return phone;
}
return CallManagerWrapper.getDefaultPhone();//不是SIP Call
}

继续查看CallManagerWrapper中的getDefaultPhone方法:

public static Phone getDefaultPhone() {  
Phone phone = null;
if (GeminiUtils.isGeminiSupport()) {//是否支持双卡
phone = ((GeminiPhone) MTKCallManager.getInstance().getDefaultPhoneGemini());
} else {
phone = CallManager.getInstance().getDefaultPhone();
}
return phone;
}

因为这里是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如下:

public Phone getDefaultPhoneGemini()  
{
return this.U;
}

这里的U是Phone对象,我们可以简单的这样理解MTK的双卡改动,将单卡流程复制一遍,然后弄一个MTKCallManager来管理总管理。

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

public void registerPhoneGemini(Phone paramPhone){  
this.U = paramPhone;
//... ...省略 }

那么这里的registerPhoneGemini()是什么时候调用的呢?我们看到TeleService的PhoneGlobals.java中onCreate方法:

public void onCreate() {  
//... ...省略
if (phone == null) {
PhoneFactory.makeDefaultPhones(this);
// Get the default phone
phone = PhoneFactory.getDefaultPhone();
//... ...省略
registerPhone();
//... ...省略
}
//... ...省略
}

这里为什么要找到PhoneGlobals中呢?这要说道Phone的启动流程了,后面再介绍吧。在第一次启动时phone == null,因此就会执行其中的makeDefaultPhones方法:

public static void makeDefaultPhones(Context context) {  
否支持双卡
if (FeatureOption.MTK_GEMINI_SUPPORT == true){
SystemProperties.set(Phone.GEMINI_DEFAULT_SIM_MODE, String.valueOf(RILConstants.NETWORK_MODE_GEMINI));
MTKPhoneFactory.makeDefaultPhone(context, RILConstants.NETWORK_MODE_GEMINI);
}else{
SystemProperties.set(Phone.GEMINI_DEFAULT_SIM_MODE, String.valueOf(RILConstants.NETWORK_MODE_WCDMA_PREF));
MTKPhoneFactory.makeDefaultPhone(context, RILConstants.NETWORK_MODE_WCDMA_PREF);
}
//... ...省略
}

接下来找到MTKPhoneFactory中的makeDefalutPhone方法:

public static void makeDefaultPhone(Context paramContext, int paramInt)  
{
//如果是Gemini那么S=RILConstants.NETWORK_MODE_GEMINI
//如果不是Gemini那么S=RILConstants.NETWORK_MODE_WCDMA_PREF
S = paramInt;
makeDefaultPhone(paramContext);
}

public static void makeDefaultPhone(Context paramContext) {
synchronized (Phone.class) {
if (!M) {
//... ...省略 创建本地socket服务端
new LocalServerSocket("com.android.internal.telephony");
N = new DefaultPhoneNotifier();

//... ...省略 获取Phone Type
int i1 = getPhoneType(j);
if (i1 == 1) { //if phoneType == PhoneConstants.PHONE_TYPE_GSM
I = new RIL(paramContext, localInterruptedException1, k, 0);
UiccController.make(paramContext, I);
H = new PhoneProxy(new GSMPhone(paramContext, I, N));
Rlog.i("PHONE", "Creating GSMPhone");
} else if (i1 == 2) { //if phoneType == PhoneConstants.PHONE_TYPE_CDMA
I = new RIL(paramContext, localInterruptedException1, k, 0);
UiccController.make(paramContext, I);
H = new PhoneProxy(new CDMAPhone(paramContext, I, N));
Rlog.i("PHONE", "Creating CDMAPhone");
} else if (i1 == 4) { //if phoneType == PhoneConstants.PHONE_TYPE_GEMINI
//这里DefaultPhoneNotifier的参数是指定SIM卡id
//... ...省略
//GEMINI_SIM_NUM = 2
int[] arrayOfInt = new int[PhoneConstants.GEMINI_SIM_NUM];
//... ...省略
//... ...arrayOfInt[0]和arrayOfInt[1]均=1
//... ...获取RILJ对象这里的RIL构造方法最后一个参数是SimId
//... ...int k = CdmaSubscriptionSourceManager.getDefault(paramContext);
I = new RIL(paramContext, arrayOfInt[0], k, 0);
J = new RIL(paramContext, arrayOfInt[1], k, 1);

//... ...省略 初始化GSMPhone数组
GSMPhone[] arrayOfGSMPhone = new GSMPhone[PhoneConstants.GEMINI_SIM_NUM];

arrayOfGSMPhone[0] = new GSMPhone(paramContext, I, N, 0);

arrayOfGSMPhone[1] = new GSMPhone(paramContext, J, O, 1);

if (PhoneConstants.GEMINI_SIM_NUM == 2) {
//这里的H实际上为GeminiPhone对象,而GeminiPhone extends Handler implements Phone
H = new GeminiPhone(new PhoneProxy(arrayOfGSMPhone[0]), new PhoneProxy(arrayOfGSMPhone[1]), i2);
}
//... ...省略
}
}
}
}

这里的H 实际上是GeminiPhone对象,而GeminiPhone extends Handler implement Phone,因此H实际上在这里完成了实例化,GeminiPhone负责双卡管理,对于GeminiPhone这里就再去细究了。通过代码可以看到最终我们是通过PhoneProxy来获取到的Phone对象,而这里的Phone对象实际上为GSMPhone,arrayOfGSMPhone数组可以看到。这里完成H对象(Phone对象)的赋值后,我们可以看到PhoneGlobals的onCreate中:

phone = PhoneFactory.getDefaultPhone();  
registerPhone();

通过getDefalutPhone()方法获取phone对象:

public static Phone getDefaultPhone() {  
turn MTKPhoneFactory.getDefaultPhone();
}

以及:

public static Phone getDefaultPhone()  
{
return H;
}

最终调用到registerPhone方法:

private void registerPhone() {  
mCM = CallManager.getInstance();
if (GeminiUtils.isGeminiSupport()) {
mCMGemini = MTKCallManager.getInstance();
//mCMGemini是MTKCallManager对象,这里完成了phone注册
mCMGemini.registerPhoneGemini(phone);
} else {
mCM.registerPhone(phone);
}
}

回过头来,我们终于找到了

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(来电)流程,敬请期待。

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

 
相关文章

手机软件测试用例设计实践
手机客户端UI测试分析
iPhone消息推送机制实现与探讨
Android手机开发(一)
 
相关文档

Android_UI官方设计教程
手机开发平台介绍
android拍照及上传功能
Android讲义智能手机开发
相关课程

Android高级移动应用程序
Android系统开发
Android应用开发
手机软件测试
 
分享到
 
 


android人机界面指南
Android手机开发(一)
Android手机开发(二)
Android手机开发(三)
Android手机开发(四)
iPhone消息推送机制实现探讨
手机软件测试用例设计实践
手机客户端UI测试分析
手机软件自动化测试研究报告
更多...   


Android高级移动应用程序
Android应用开发
Android系统开发
手机软件测试
嵌入式软件测试
Android软、硬、云整合


领先IT公司 android开发平台最佳实践
北京 Android开发技术进阶
某新能源领域企业 Android开发技术
某航天公司 Android、IOS应用软件开发
阿尔卡特 Linux内核驱动
艾默生 嵌入式软件架构设计
西门子 嵌入式架构设计
更多...