资料库
读者如对 Android Telephony 相关资料有需求可访问 Github 仓库
1. IMS 启动
1.1 IMS 开关流程
- IMS 的开关在 Settings 的网络设置模块中,点击启用 VoLTE 开关,即会通过 ImsManager 去进行打开IMS 功能的流程
- ImsManager 调用 TelephonyManager 的接口,最终会经过 PhoneInterfaceManager 调用 ImsResolver 进入 IMS 框架流程
- ImsResolver 是上层的一个接入接口,在该流程中需要 ImsServiceController 进行跨进程的服务绑定,最终绑定 vendor 厂商提供的 ims.apk 中的 ImsService 作为服务,vendor 中的 ImsService 其实是继承于 framework 中的 ImsService
- 不同平台有不同的 ims.apk 实现,以高通为例,其内部以 ImsServiceStub 为最终实现子类,之后通过类似 RILJ 的 ImsSenderRxr 作为请求分发器,将请求下发到 RIL层中
- 底层响应通过 ImsRadioResponse 返回到 SenderRxr 中,紧接着一路返回到上层
1.2 需注意的细节
- Android Q 中网络相关的设置已经从 TeleService 中移到了 Settings 下,TeleService 中的代码并没有删除,Android 提供了两种网络设置样式,V1的配置值依然会进入 TeleService 网络设置
- Android Q 对 IMS 有一些结构改变,除了 ImsManager 作为总的管理器之外,引入了 MMTelManager 来管理 IMS 的 Feature 和 Config 等
- Android Q 中 IMS 相关的 GTS 有一个 MMTelFeatureConnection 多次新建但未销毁 callback 导致的超时问题
- IMS 主要分为两种类型的实现,一个是 MMTel,另一个是 RCS 。MMTel 实现的功能主要包括 ViLTE、VoLTE、WifiCalling,其中 ViLTE、VoLTE 都走 data 数据通道,WifiCalling 走 wifi 连接通道并且可支持语音及视频通话;RCS 相关 Feature 在 Android 源码中没有具体实现,但在 Google 的 GMS 包中有支持。
2. IMS 连接建立
2.1 IMS 连接建立流程
在 IMS开关打开后,上层发起对 IMS 网络的请求会触发 IMS 连接的创建,该流程与 DATA 数据连接建立 大致相同,只需将用于建立连接的 APN 改为 IMS APN 的配置。
2.2 需注意的问题
- IMS 连接建立失败通常有几方面的原因
- 首先需要查看 CarrierConfig 是否配置正确,同时检查是否有相关 overlay 配置导致 IMS 功能未正常启用
- 其次检查 ImsService 是否正确绑定,因为 Android 原生也提供了一个 CarrierServices.apk 包含
CarrierServicesImsService
,如果未正确绑定到 vendor 厂商提供的 ims.apk 中的ImsService
,这时系统认为 IMS 服务不可用,也很可能发生连接建立失败的问题
- IMS 严重依赖运营商支持,所以在加载 IMS 配置前需要 CarrierConfig 运营商配置先加载完成,这也是需要注意的点
- ImsPhoneCallTracker 监听 IMS 来电的实现
ImsPhoneCallTracker
初始化的时候会注册监听ACTION_IMS_INCOMING_CALL
的广播接收器,并通过sendEmptyMessage(EVENT_GET_IMS_SERVICE)
方法进入内部的handler
中处理EVENT_GET_IMS_SERVICE
消息- 此时会调用
getImsService()
方法获取 ImsService,并在该方法中添加回调接口mNotifyStatusChangedCallback
.这个ImsServiceProxy.INotifyStatusChanged
对象在初始化的时候会通过ImsManager的getImsServiceStatus()
方法获取ImsService的状态,如果状态为ImsFeature.STATE_READY
,则调用startListeningForCalls()
方法开始监听来电 - 在这个方法中会调用
createIncomingCallPendingIntent()
方法创建一个Action为ImsManager.ACTION_IMS_INCOMING_CALL
的PendingIntent,然后通过ImsManager的open()
方法将这个PendingIntent传递给 ImsService,这样在来电的时候ImsService就会发出ImsManager.ACTION_IMS_INCOMING_CALL
广播,ImsPhoneCallTracker 也就可以收到 IMS 来电广播了