前置文章:
《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分成四个部分: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);
- }
- 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);
- }
- 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());
- }
- public ContactsCallOptionHandler(Context activityContext, CallOptionHandlerFactory callOptionHandlerFactory) {
- super(callOptionHandlerFactory);
- mActivityContext = activityContext;
- }
- mCallOptionHandler = new ContactsCallOptionHandler(getActivity(),
- new ContactsCallOptionHandlerFactory());
- mCallOptionHandlerList.add(callOptionHandlerFactory.getFirstCallOptionHandler());
- //等价于
- mCallOptionHandlerList.add(new ContactsCallOptionHandlerFactory().getFirstCallOptionHandler());
- mCallOptionHandlerList.getFirst().handleRequest(request);
- //等价于
- new ContactsCallOptionHandlerFactory().getFirstCallOptionHandler().handleRequest(request);
- 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);
- @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);
- }
- }
这里比较重要了,这个mSuccessor对象是什么呢?它的定义在抽象类CallOptionBaseHandler中,而FirstCallOptionHandler是CallOptionBaseHandler的子类:
- protected CallOptionBaseHandler mSuccessor;
- ListIterator<CallOptionBaseHandler> iterator = mCallOptionHandlerList.listIterator();
- CallOptionBaseHandler previousHandler = iterator.next();
- while (iterator.hasNext()) {
- CallOptionBaseHandler currentHandler = (CallOptionBaseHandler)iterator.next();
- previousHandler.setSuccessor(currentHandler);//也就是说前一个对象的mSuccessor对象是当前的OptionHanderHandler
- previousHandler = currentHandler;
- }
- 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()
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);
- }
- @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);
- //... ...省略
- }
- }
- 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
- }
这里通过制定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);
- }
- }
- }
TeleService中Call处理部分,实际上主要是后台逻辑处理,Android 4.4 Phone最重要的特点就是将显示和逻辑分离。这块与Android 4.2改动并不大,只是从原来的Phone中分离了出来。
TeleService执行时序图如下:
Framework Telephony处理拨号请求
这里的调用和参数传递也比较多,有几个关键点需要提一下。当我们跳转到CallManager的dial方法后,会执行到以下代码获取Connection:
- result = basePhone.dial(dialString);
- phone = PhoneUtils.pickPhoneBasedOnNumber(mCM, scheme, number, sipPhoneUri);
- 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
- }
- public static Phone getDefaultPhone() {
- Phone phone = null;
- if (GeminiUtils.isGeminiSupport()) {//是否支持双卡
- phone = ((GeminiPhone) MTKCallManager.getInstance().getDefaultPhoneGemini());
- } else {
- phone = CallManager.getInstance().getDefaultPhone();
- }
- return phone;
- }
因为这里是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如下:
- public Phone getDefaultPhoneGemini()
- {
- return this.U;
- }
那么这里的Phone是如何赋值的呢,可以看到有一个registerPhoneGemini的方法:
- public void registerPhoneGemini(Phone paramPhone){
- this.U = paramPhone;
- //... ...省略 }
- public void onCreate() {
- //... ...省略
- if (phone == null) {
- PhoneFactory.makeDefaultPhones(this);
- // Get the default phone
- phone = PhoneFactory.getDefaultPhone();
- //... ...省略
- registerPhone();
- //... ...省略
- }
- //... ...省略
- }
- 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);
- }
- //... ...省略
- }
- 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);
- }
- //... ...省略
- }
- }
- }
- }
- phone = PhoneFactory.getDefaultPhone();
- registerPhone();
- public static Phone getDefaultPhone() {
- turn MTKPhoneFactory.getDefaultPhone();
- }
- public static Phone getDefaultPhone()
- {
- return H;
- }
- 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);
整个时序图如下:
总结
整个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(来电)流程,敬请期待。
对于使用原生或者高通代码的童鞋可以看看这篇文章,这位童鞋的分析还是很到位的,心急的可以直接跳到最后去看框架图。