Telephony解析之VoiceCall

本文代码基于Android 9.0

概述

VoiceCall就是我们通常所说的打电话是基于系统中Telephony框架的具体应用情景,Telephony中涉及的其他通讯功能有ServiceState(服务状态)、DataConnection(数据链接)、SMS(短信),这篇文章重点讲解Call(通话)

1.MO(Mobile Origination Call)主叫,操作流程:拨号,启动UI界面,更新通话状态;

2.MT(Mobile Termination Call)被叫,操作流程:响铃,启动UI界面,更新通话状态。

VoiceCall框架

VoiceCall是一个可以通话的手机功能,Android系统中的VoiceCall的组成结构主要由下面几部分构成

1.Dialer(IncallUI) 为用户交互操作提供UI界面

2.Telephony Service 封装了控制,查询Telephony等功能

3.Telephony Framework 提供通话各种功能调用和状态查询,负责上层和Modem的通信

4.RIL 负责拨号,Sip,package收发等基本操作

voice_call_action

具体个模块详细信息请查看下表:

模块名称 模块路径 模块功能
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/Telecomm App侧维护Call,call的相关处理都在TeleCom中进行。
TeleService FW frameworks/opt/telephony 和RIL通信,完成Call的基本通话功能以及其他相关业务。
Telecom FW frameworks/base/telecom 确保TeleCom的独立性,减少TeleCom和其他模块的直接交互。

VoiceCall流程

主要代码介绍

在学习VoiceCall的流程之前,先总结一下通话流程中的主要代码分布和作用

路径 主要代码文件 代码功能介绍
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守护进程

主动呼叫(MO)

对于熟悉Android O之前RIL的开发者来说,Android O上RIL最大的改变就是将socket通信换成了binder通信,只不过是/dev/hwbinder,而不是/dev/binder。Binder IPC的开发模式是服务端注册service, 客户端获取service,然后调用相关API。Server端RILD不再是socket监听,而是注册service; RILJ也不再是连接socket,而是获取service,持有引用。通信方式的改变导致RILD和RILJ都发生了改变,但是这个变化并不算大,以前的轮廓还在。

voice_call_mo01

被动接听(MT)

2.2 Voice Call中的基本概念:

要了解Voice Call,需要熟悉其中的基本概念。Voice Call的几个基本概念包括:

Phone:Phone是一个最基本的概念,用来控制Telephony相关模块的处理

Call:此处是TeleService中的Call,是用来管理Connection的,有且仅有三种Call存在:foregroundcall, backgroundcall, ringingcall

CallList:App侧会维护Call的CallList,如果CallList变更,界面会做出对应的响应操作

Connection: 一个通路。

Call和Connection并不是一一对应的,一个Connection必须要依附于一个Call, 一个Call可以有多个Connection。在多方通话中,一个Call会对应多个Connection。最多可以同时有7个Connection存在,对于一个Call中最多有5个Connection。

Example 2-2 最多允许的connection数

1
2
static final int MAX_CONNECTIONS = 7;   // only 7 connections allowed in GSM
static final int MAX_CONNECTIONS_PER_CALL = 5; // only 5 connections allowed per call

Call的基本状态如下:

DIALING,CONNECTING,ACTIVE,ON_HOLD,DISCONNECTING,DISCONNECTED,RINGING

2.3 各模块之间的调用关系

Voice Call中有很多模块,这里我们会介绍各模块之间的调用关系:

02

在上图中,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通信比较方便。

2.4 Android侧Call中的关键机制介绍:

消息注册机制:

在TeleService和TeleService Framework中采用的是消息注册机制。

消息注册机制更加丰富了MessageHandle的流程,它把过程严格阶段化了,分成消息注册和通知消息处理两个部分,让人一目了然。

消息注册机制的总体思想是:一个对象中开辟一个空间用于存放Message,当调用regist方法时将Message存放进去,当其调用notify方法时将所有Message取出并发送到MessageQueue中等待处理。

这里用到了观察者模式,下面是TeleService里面的消息注册机制的对比。

03

注:观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。

模式中的角色

  抽象主题(Subject):它把所有观察者对象的引用保存到一个聚集里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。

  具体主题(ConcreteSubject):将有关状态存入具体观察者对象;在具体主题内部状态改变时,给所有登记过的观察者发出通知。

  抽象观察者(Observer):为所有的具体观察者定义一个接口,在得到主题通知时更新自己。

  具体观察者(ConcreteObserver):实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题状态协调。

3 Voice Call主要流程

这里会介绍Voice Call的主要流程,包括:MO,MT

3.1 MO Call时序图:

04

3.2 MT Call时序图:

05