本篇文章介绍M(Marshmallow) Telephony的MO(Mobile Original) call 的流程。

1.拨号App中输入号码并拨号,Android的源生的拨号App为Dialer(packages/apps/Dialer)

下面看一下在输入完号码,点击拨号按钮后,Dialer中都做了什么事情。

首先触发的是UI点击事件

DialpadFragment

handleDialButtonPressed()

/**
     * In most cases, when the dial button is pressed, there is a
     * number in digits area. Pack it in the intent, start the
     * outgoing call broadcast as a separate task and finish this
     * activity.
     *
     * When there is no digit and the phone is CDMA and off hook,
     * we're sending a blank flash for CDMA. CDMA networks use Flash
     * messages when special processing needs to be done, mainly for
     * 3-way or call waiting scenarios. Presumably, here we're in a
     * special 3-way scenario where the network needs a blank flash
     * before being able to add the new participant.  (This is not the
     * case with all 3-way calls, just certain CDMA infrastructures.)
     *
     * Otherwise, there is no digit, display the last dialed
     * number. Don't finish since the user may want to edit it. The
     * user needs to press the dial button again, to dial it (general
     * case described above).
     */

通过注释可以知道这个函数要把要拨打的号码打包到一个intent里,然后发出去。(CDMA的我不懂~~~)

DialerUtils

打包好intent之后,调用DialerUtils的静态方法startActivityWithErrorToast(getActivity(), intent),看一下这个方法要做什么事情。

这个方法估计是要显示一个界面,就是点击拨号按钮之后该显示的界面~

然后,最主要的是有下面这良好代码。

final TelecomManager tm =
                        (TelecomManager) context.getSystemService(Context.TELECOM_SERVICE);
tm.placeCall(intent.getData(), intent.getExtras());

从这两行代码中可以看出,Dialer App拨号需要用到Framework的打电话接口placeCall

并且从TelecomManager的函数原型(placeCall(Uri address, Bundle extras))可以看到,使用这个接口需要提供这两个参数,那么这两个参数分别代表什么意思?

/**
     * Places a new outgoing call to the provided address using the system telecom service with
     * the specified extras.
     *
     * This method is equivalent to placing an outgoing call using {@link Intent#ACTION_CALL},
     * except that the outgoing call will always be sent via the system telecom service. If
     * method-caller is either the user selected default dialer app or preloaded system dialer
     * app, then emergency calls will also be allowed.
     *
     * Requires permission: {@link android.Manifest.permission#CALL_PHONE}
     *
     * Usage example:
     * <pre>
     * Uri uri = Uri.fromParts("tel", "12345", null);
     * Bundle extras = new Bundle();
     * extras.putBoolean(TelecomManager.EXTRA_START_CALL_WITH_SPEAKERPHONE, true);
     * telecomManager.placeCall(uri, extras);
     * </pre>
     *
     * The following keys are supported in the supplied extras.
     * <ul>
     *   <li>{@link #EXTRA_OUTGOING_CALL_EXTRAS}</li>
     *   <li>{@link #EXTRA_PHONE_ACCOUNT_HANDLE}</li>
     *   <li>{@link #EXTRA_START_CALL_WITH_SPEAKERPHONE}</li>
     *   <li>{@link #EXTRA_START_CALL_WITH_VIDEO_STATE}</li>
     * </ul>
     *
     * @param address The address to make the call to.
     * @param extras Bundle of extras to use with the call.
     */

看注释,这方法特别简单粗暴,可以很快的提取需要的了解的信息。这address就是要拨打的电话号码的Uri形式,而extras携带的附加信息可以通过注释了解,各个参数通过字面意思就可以了解个大概~。

2.Telecom的处理,这部分代码很多,需要一步一步的对照着代码来~,不会贴很全的代码,但会罗列主要的代码。

ITelecomService service = getTelecomService();

service.placeCall(address, extras == null ? new Bundle() : extras,
                        mContext.getOpPackageName());

这个service是package/service/Telecomm TelecomServiceImpl,通过AIDL实现进程间通信,

private final ITelecomService.Stub mBinderImpl = new ITelecomService.Stub()

这个需要加下log打印来验证一下代码是不是跑在不同的线程~看一下在Manifest文件里的配置~(经验证,是跑在不同进程或者线程~)

<service android:name=".components.TelecomService"
                android:singleUser="true"
                android:process="system">

android:process="system" 这个是啥意思?是不是会被系统启动~独立线程?

在TelecomServiceImpl 的placeCall里主要加上了call的权限信息,UserHandle,不知道这个是干啥的。

->new UserCallIntentProcessor(mContext, userHandle).processIntent(intent,
                            callingPackage, hasCallAppOp && hasCallPermission);

->processOutgoingCallIntent(intent, callingPackageName, canCallNonEmergency);//video state, call permission 的判断处理

->         intent.putExtra(CallIntentProcessor.KEY_IS_PRIVILEGED_DIALER,
                isDefaultOrSystemDialer(callingPackageName));
        sendBroadcastToReceiver(intent)

-> intent.setClass(mContext, PrimaryCallReceiver.class);

mContext.sendBroadcastAsUser(intent, UserHandle.OWNER);

-> PrimaryCallReceiver -> getTelecomSystem().getCallIntentProcessor().processIntent(intent); //上面不知道为什么要这么写或者说为什么要这样设计

-> CallIntentProcessor -> processOutgoingCallIntent(mContext, mCallsManager, intent); //这里会new一个telecom的call

-》Call call = callsManager.startOutgoingCall(handle, phoneAccountHandle, clientExtras);

这里的PhoneAccountHandle的不同应该代表的是不同的卡,如果现在有一个正在进行的mForegroundCall,那么这个新的call的PhoneAccountHandle会被设置成和当前这个mForegroundCall的PhoneAccountHandle一样的值。

phoneAccountHandle =
                    mPhoneAccountRegistrar.getOutgoingPhoneAccountForScheme(handle.getScheme());// 或者通过mPhoneAccountRegistrar来获取默认的电话卡(PhoneAccountHandle),如果没有设置默认电话卡,那这个获取的PhoneAccountHandle可能应该还是为Null的。

call.setTargetPhoneAccount(phoneAccountHandle);

addCall(call);//将新call添加到CallsManager维护的mCalls中

updateCallsManagerState();

updateForegroundCall();// 根据条件来更新当前的mForegroundCall,然后会通过监听这个变化的listener来进行通知,listener.onForegroundCallChanged(oldForegroundCall, mForegroundCall);
         updateCanAddCall();//和上面一样,只不过通知的内容不同,监听者可以在CallsManager构造函数里找到(statusBarNotifier,mRinger,mInCallController...好多~)

-》NewOutgoingCallIntentBroadcaster broadcaster = new NewOutgoingCallIntentBroadcaster(
                    context, callsManager, call, intent, isPrivilegedDialer);

final int result = broadcaster.processIntent();//还是处理intent,没完没了,不知道这样写的好处是啥。

->NewOutgoingCallIntentBroadcaster processIntent() //检查号码是不是voice mail号码什么的

-> broadcastIntent(intent, number, !callImmediately) -> mContext.sendOrderedBroadcastAsUser //发广播了

-> 收到广播后           mCallsManager.placeOutgoingCall(mCall, resultHandleUri, gatewayInfo,
                    mIntent.getBooleanExtra(TelecomManager.EXTRA_START_CALL_WITH_SPEAKERPHONE,
                            false),
                    mIntent.getIntExtra(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,
                            VideoProfile.STATE_AUDIO_ONLY));

->call.startCreateConnection(mPhoneAccountRegistrar);

->mCreateConnectionProcessor.process()

->attemptNextPhoneAccount();

下面Telecom和Telephony将通过AIDL来进行通信

ConnectionServiceWrapper service =
                    mRepository.getService(
                            phoneAccount.getComponentName(),
                            phoneAccount.getUserHandle());

service.createConnection(mCall, new Response(service));

-> mBinder.bind(callback, call);

mCallbacks.add(callback), isBound = mContext.bindService(serviceIntent, connection, bindingFlags);

这里bindService的对象是Telephony的TelephonyConnectionService,成功后会回调onServiceConnected,

setBinder(binder) //mBinder = binder; 把binder保存在Telecom本地,mServiceInterface = IConnectionService.Stub.asInterface(binder);获得TelephonyConnectionService的实例?, mServiceInterface.addConnectionServiceAdapter(adapter); 把自己的adapter给对方,来进行双工通信?。具体能干啥可以看一下这个adapter怎么实现的。

handleSuccessfulConnection() -》 callback.onSuccess();  //回调刚刚设置好的callback,然后会把mCallbacks清掉

-> mServiceInterface.createConnection //这里会带上call的很多信息, 然后就在Telephony了

3.Telephony

通过bindService,Telecom获得了Telephony的远程实例,Telephony获得了Telecom的adapter,按顺序先看一下拿到adapter做了啥事。

TelephonyConnectionService 会发一条内部的handler消息, MSG_ADD_CONNECTION_SERVICE_ADAPTER

->mAreAccountsInitialized = true; //然后在添加一些连接信息。

之后,Telecom调用了mServiceInterface.createConnection,Telephony -> MSG_CREATE_CONNECTION -> createConnection

这里会根据所带的信息来建立outgoing Connection或者是incoming Connection,拨打电话当然是outgoing。

onCreateOutgoingConnection(callManagerAccount, request)// 这里面还是会详细检查好多条件,号码为null啊,voice mail,CDMA,emergency number,ServiceState,

没啥错误的话 -》placeOutgoingConnection(connection, phone, request); -》originalConnection =
                    phone.dial(number, null, request.getVideoState(), request.getExtras());

这里的phone是GSMPhone,那么代码又跑到了Framework。
4.Framework~
在GSMPhone中会处理是否要用Ims(IP Multimedia Subsystem),如果不用IMS,那么直接通过GSMCallTracker 调用RIL的dial接口拨号~。
5.IMS
如果用了IMS,那么会转而调用IMSPhone的dial接口,然后通过ImsPhoneCallTracker的接口来拨号~
synchronized Connection
    dial(String dialString, int clirMode, int videoState, Bundle intentExtras)
建立新的ImsPhoneConnection
->mPendingMO = new ImsPhoneConnection(mPhone,
                    checkForTestEmergencyNumber(dialString), this, mForegroundCall,
                    isEmergencyNumber);
->dialInternal(mPendingMO, clirMode, videoState, intentExtras);
->             ImsCall imsCall = mImsManager.makeCall(mServiceId, profile, callees, mImsCallListener);
            conn.setImsCall(imsCall);
->ImsManager.java makeCall
ImsCallSession session = createCallSession(serviceId, profile);
->return new ImsCallSession(mImsService.createCallSession(serviceId, profile, null));
-->mImsService = IImsService.Stub.asInterface(b); //IImsService.Stub 这个要看各个厂商自己具体实现~
->call.start(session, callees[0]);
ImsCall.java start(ImsCallSession session, String callee)
-->session.start(callee, mCallProfile);
这个session 是 ImsCallSession.java
-> ImsCallSession miSession.start(callee, profile)
这个miSession是远程实例,也应该是厂商自己来实现的。
最终调用的还是RIL的接口dial

Telephony MO CALL/IMS CALL相关推荐

  1. Android 9.0 IMS通话流程

    简介: VoLTE是基于IMS的语音业务,它是一种IP数据,就是我们熟知的高清语音通话. 第一部分 拨出流程(MO) IMS通话流程可以在GSM的通话流程的基础上进行研究,整体流程都差不多,就是在一些 ...

  2. 5G VoNR+之IMS Data Channel概念

    VoNR,即Voice over New Radio,是VoLTE(Voice over LTE)的演进版本.相比于VoLTE,VoNR除了空口变成了NR之外,其他IMS相关的基本架构和流程与VoLT ...

  3. Dialer中界面组成、Call对象和log分析

    主要内容 1. Call涉及的目录结构及框架结构 2. InCallUI层的基本架构(所涉及的Presenter.Fragment及Activity) 3. Call的几种状态(对应phone状态)及 ...

  4. 5G会用什么样的语音通信方案?

    [摘要]本文对5G网络下包含VoNR及EPS fallback等在内的语音技术进行了介绍,涉及5G语音方案相关的网络架构.基本业务流程等层面.并针对现有语音方案流程设计,提出了存在的问题,以及可能的解 ...

  5. Android Dialer--通讯整体过程分析

    1.1 目录结构 packages/apps/Dialer+InCallUI  packages/services/Telecomm    packages/services/Telephony  f ...

  6. 5G来了,会用什么样的语音解决方案?

    [摘要]本文对5G网络下包含VoNR及EPS fallback等在内的语音技术进行了介绍,涉及5G语音方案相关的网络架构.基本业务流程等层面.并针对现有语音方案流程设计,提出了存在的问题,以及可能的解 ...

  7. NB-IoT系列协议--3GPP--Release 16--TS 36.300--总体描述;阶段2

    NB-IoT系列协议--3GPP--Release 16--TS 36.300--总体描述:阶段2 1.范围 2.定义 3.缩写 4.总体架构 4.1 概述 4.2 功能划分 4.3 无线电协议体系结 ...

  8. Android5.1 Telephony流程分析——拨打电话流程(MO CALL)

    本文代码以MTK平台Android 5.1为分析对象,与Google原生AOSP有些许差异,请读者知悉. 此图主要是根据Android源代码拨打电话流程来绘制,记录了电话拨打的主要过程: 参考博客:h ...

  9. Android4.4 Telephony流程分析——去电(MO)流程

    本文代码以MTK平台Android 4.4为分析对象,与Google原生AOSP有些许差异,请读者知悉. 下图为去电时序图: 右键复制图片地址,在浏览器中打开即可查看大图. 未完待续,有不对的地方,请 ...

最新文章

  1. 十三、序列化和反序列化(部分转载)
  2. 在leangoo里怎么设置看板周期,过滤看板数据?
  3. R语言ggplot2可视化通过se参数和level参数设置置信区间的显示与否以及置信区间的范围(95%、90%、50%)
  4. 基于贝叶斯算法实现简单的分类(java)
  5. 如何通过终端快速删除文件和目录(bash shell)[关闭]
  6. sqlmap os shell解析
  7. 【Android 逆向】ptrace 函数 ( C 标准库 ptrace 函数简介 | ptrace 函数真实作用 )
  8. 2D 游戏引擎 AlloyGameEngine
  9. GDCM:gdcm::CodeString的测试程序
  10. leetcode 581. 最短无序连续子数组(详解普通 / 进阶 / 单调栈解法,Java版)
  11. 使用node https module创建服务器遇到的mac verify failure错误消息
  12. python编程口诀_少儿Python编程中的算术与技巧
  13. 【网络编程】——windows socket 编程
  14. QScrollArea滚动条
  15. 数据结构与算法——贪心算法汇总整理
  16. 最新深度学习文本分类模型汇总(github开源)
  17. Docker详解(十四)——Docker网络类型详解
  18. Android layoutInflate.inflate 方法具体解释,removeView()错误解决
  19. DCGAN训练人脸照片,pytorch
  20. tftp怎么给服务器传文件,(tftp) - 在本机和tftp服务器之间使用TFTP协议传输文件...

热门文章

  1. 农村电商是什么,如何做农村电商?
  2. 服务器30hz显示器240hz,这次玩家说了算 三款240Hz显示器谁更强
  3. 坐拥上亿流量,星空华文能否在港股舞台上脱颖而出?
  4. poj1985 / poj2631(树的直径)
  5. 移动机器人技术(6)-- 机器人控制策略
  6. 2021 - 45周(App合规自查)
  7. Python --欧洲中心资料下载
  8. java html文本编辑器,基于Java WebHTML在线文本编辑器解决方案.doc
  9. 博弈论问题,弱弱的分析
  10. Crontab执行java/spark-shell/spark-submit 异常解决方法