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框架图

具体框架图请看下图:
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
  • 各模块之间的调用关系,如下图:
    VoiceCall流程解析

注:

  • 在上图中,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流程:
VoiceCall流程解析

被动接听(MT)流程

继续采用时序图的方式了解整个MT流程:
VoiceCall流程解析