VoiceCall流程解析
本文章代码基于Android 9.0
概述
VoiceCall就是我们通常所说的打电话是基于系统中Telephony框架的具体应用情景,Telephony中涉及的其他通讯功能有ServiceState(服务状态)、DataConnection(数据链接)、SMS(短信)、Contacts(联系人)…这篇文章重点讲解Call(通话)
- MO(Mobile Origination Call)主叫,操作流程:拨号,启动UI界面,更新通话状态。
- MT(Mobile Termination Call)被叫,操作流程:响铃,启动UI界面,更新通话状态。
框架
Android系统中的VoiceCall的组成结构主要由下面几部分构成:
- Dialer(IncallUI) 为用户交互操作提供UI界面
- TeleService 封装了控制,查询Telephony等功能
- Telephony(Framework )提供通话各种功能调用和状态查询,负责上层和Modem的通信
- RIL 负责拨号、Sip、package收发等基本操作
VoiceCall框架图
具体框架图请看下图:
具体各个模块的详细信息请看下表:
Module | Path | Function |
---|---|---|
Dialpad | packages/apps/Dialer/ | 拨号盘 |
CallLog | packages/apps/Dialer/ | 通话记录。其中显示的信息是从数据库中读出来的。在通话结束时,会将Call的信息存储到CallLog数据库中 |
InCallUI | packages/apps/Dialer/ | 通话中的画面显示,在Android原生设计中,该模块只处理界面相关的内容 |
TeleService | packages/services/Telephony | TeleService Framework 和 TeleCom Framework沟通的介质 |
CallSettings | packages/services/Telephony | 里面多数是增值服务(SS)的设置,设置的过程中,会向MODEM侧发请求。比如:呼叫转移(CF) |
TeleCom | packages/services/Telecom | App侧维护Call,call的相关处理都在TeleCom中进行 |
TeleService FW | frameworks/opt/telephony | 和RIL通信,完成Call的基本通话功能以及其他相关业务 |
Telecom FW | frameworks/base/telecom | 确保TeleCom的独立性,减少TeleCom和其他模块的直接交互 |
流程相关主要代码介绍
在了解VoiceCall流程之前我们需要先对该流程涉及的主要代码、分布和功能进行了解:
Path | Class | Function |
---|---|---|
packages/apps/Dialer | DialpadFragment.java | 拨号盘 |
packages/apps/Dialer | InCallScreen.java | 通话界面(通话信息、状态显示,通话控制按钮) |
packages/services/Telecomm | NewOutgoingCallIntentBroadcaster.java | 接收CALL、CALL_PRIVILEGED、CALL_EMERGENCY类型的ACTION,发送ACTION_NEW_OUTGOING_CALL广播 |
packages/services/Telephony | PhoneApp.java | 创建Phone对象,控制耳机、蓝牙、感应器、背景灯和Call状态等 |
packages/services/Telephony | PhoneUtils.java | 通话控制辅助类 |
packages/services/Telephony | CallNotifier.java | 电话应用程序模块,用于侦听电话状态更改以及来自电话层的各种其他事件,并触发任何生成的UI行为(例如启动Incoming Call UI,播放通话音,更新通知,编写通话记录条目等) |
frameworks/opt/telephony | Phone.java | Phone对象的抽象接口 |
frameworks/opt/telephony | CallManager.java | 为PhoneApp提供了一个访问和控制调用的抽象层,负责Framework和APP层的交互 1.呼叫控制和操作,例如dial()和hangup()2.通道功能,例如CanConference()3.注册通知 |
frameworks/opt/telephony | CallTracker.java | 和RIL.java交互,发起Call相关请求、跟踪Call状态 |
frameworks/opt/telephony | ServiceStateTracker.java | 和RIL.java交互,跟踪服务状态变化,并发起相关消息通知,SIM卡注册服务,SIM卡状态,手机信号等功能 |
frameworks/opt/telephony | DcTracker.java | 和RIL.java交互,跟踪数据链接相关状态 |
frameworks/opt/telephony | RIL.java | 和RIL(native)交互,完成AT命令执行,Call状态更新 |
frameworks/base/telephony | TelephonyManager.java | 提供对设备上telephony services信息的访问 |
hardware/ril | ril.cpp | native层的RIL |
hardware/ril | rild.c | RILD守护进程 |
VoiceCall相关的基本概念
在了解MO/MT流程之前,我们先对通话相关的概念进行一个整理:
- Phone对象:Phone是一个最基本的概念,用来控制Telephony相关模块的处理
- Call:此处是TeleService中的Call,是用来管理Connection的,有且仅有三种Call存在:foregroundcall, backgroundcall, ringingcall
- CallList:Dialer侧会维护Call的CallList,如果CallList变更,界面会做出对应的响应操作
- Connection: 一个通话线路
Call和Connection并不是一一对应的,一个Connection必须要依附于一个Call, 一个Call可以有多个Connection。在多方通话中,一个Call会对应多个Connection。最多可以同时有7个Connection存在,对于一个Call中最多有5个Connection。
static final int MAX_CONNECTIONS = 7;
static final int MAX_CONNECTIONS_PER_CALL = 5;
- Call的基本状态:DIALING,CONNECTING,ACTIVE,ON_HOLD,DISCONNECTING,DISCONNECTED,RINGING
- 各模块之间的调用关系,如下图:
注:
- 在上图中,TeleCom Service接受到应用发来的Intent之外,通过TeleCom Framework进行通信。其中TeleCom Service 以及 TeleCom Framewokr,我们统称为Telecom,其主要负责所有Call的业务逻辑。
- 上层APP(InCallUI)接触到的Phone、Call以及Connection对象,实际上是Telecom Framework的Phone、Call和Connection对象,并不是Telephony Framework中的GSMPhone、GsmCall和GsmConnection。其中,Telecom Framework,负责通话数据的传递以及控制指令的下发。而Telecom Service中的CallsManager则负责所有通话数据以及指令的处理,并将结果传递给TelecomFramework。
- 对于CallSetting,需要发消息到网络。TeleCom模块仅用于处理Call相关的操作,所以把CallSetting放在TeleService中,和MODEM通信比较方便。
- Call相关的关键机制(消息***制)
在TeleService和TeleService Framework中采用的是消息***制。
消息***制更加丰富了MessageHandle的流程,它把过程严格阶段化了,分成消息注册和通知消息处理两个部分,让人一目了然。
消息***制的总体思想是:一个对象中开辟一个空间用于存放Message,当调用regist方法时将Message存放进去,当其调用notify方法时将所有Message取出并发送到MessageQueue中等待处理。
这里的消息***制用到了观察者模式,下面是TeleService里面的消息***制的UML图:
主动呼叫(MO)流程
我们采用时序图的方式来了解整个MO流程:
被动接听(MT)流程
继续采用时序图的方式了解整个MT流程: