主要内容

1. Call涉及的目录结构及框架结构

2. InCallUI层的基本架构(所涉及的Presenter、Fragment及Activity)

3. Call的几种状态(对应phone状态)及上报流程

4. GSM与IMS MO流程的差异

5. 分析问题的常用log

希望你在看完本篇以后能够:

1.快速找到Call界面某个小时内容对应的fragment及presenter

2.结合log快速定位当前call的状态

1. Call涉及的目录结构及框架结构

1.1 目录结构

packages/ apps/Dialer/

packages/apps/InCallUI

packages/services/Telecomm

packages/ services/Telephony

framework/base/telecomm

framework/opt/telephony

(vendor/…/ ims Ims Call)

Dialer  

拨打电话的入口,来电不会经过Dialer。但是拨打电话的出口不光是Dialer,在联系人和短信里也有拨打电话的出口。代码运行在dialer进程。

InCallUI

负责显示通话界面的信息,来电信息。dialer进程。

Telecomm

处理Intent,发送广播,设置call的状态,audio状态。system_process和telecomm:ui进程。

Telephony

向下层传递拨号,注册了很多广播,申请很多权限(service data sms wap network)。 phone进程

telecomm 

提供placeCall的接口(自android M开始),创建outgoingCall的connection,通知上层成功建立connection

telephony

拨号 也就是dial命令的下发,但是如果是Ims网络就会有下面一步

Vendor/ims

创建ImsConnection,ImsCall,拨号。phone进程。

1.2 框架结构

这只是框架上的一个大致结构

在实际的流程中并不一定是自上而下或者 自下而上的,也有可能跳过某个模块直接 传递信息。

比如在Dialer拨号的时候,就是直接调用 framework/base/telecmm中 TelecomManager的placeCall接口拨打 电话。

2. InCallUI层的基本架构(所涉及的Presenter、Fragment及Activity)

2.1InCallUI内有多个对应的Presenter和Fragment

Presenter和Fragment的关系: Fragment直接控制界面上的控件,并处理一些简单的逻辑,对应的Presenter处理稍复杂的逻辑。

CallCardFragment

CallCarfPresenter

CallButtonFragment

CallButtonPresenter

CallCard和CallButton是绑定在一起显示的,有CallCard就一定会有CallButton

CallCard显示拨打的电话的信息,包括联系人姓名,号码,通话时长,通话类型等(稍后有展示)

CallButton包括可以对当前通话进行的操作,如通话保持,通话静音,通话录音等。

VideoCallFragment

VideoCallPresenter

主要是视频内容,在进入退出视频模式时同时处理camera、audio相关信息。

AnswerFragment

AnswerPresenter

显示新来电,或者视频升级请求,重点在于对不同类型的通话显示不同的选项(也可根据运营商进行不同配置)。

DialpadFragment

DialpadPresenter

拨号盘,添加通话的时候显示。一般没什么问题,之前有该显不显的问题,同时dialpad的显示会影响endCallButton的大小,两者是同步变化的。

ConferenceManagerFragment

ConferenceMangerPresenter

没遇到过这里的问题,只是准备PPT的时候才看到这个。

InCallActivity启动的时候,在显示完动画后,调用showCallCardFragment()显示CallCardFragment(CallCardFragment本身也有动画)然后Fragment内new Presenter。

其他几个也有各自的显示流程,不一定是在InCallActivity的动画显示后立刻show出来。

另: VideoCallFragment不是通过 showFragment()显示的。

2.2 通话界面布局分析

注:界面被轻量定制,并非和原生完全一样。

图1 CallCardFragment和CallButtonFragment

图中除了priamry_card_info.xml和call_button_fragment.xml是布局文件,其他标注均为控件id。

AnswerFragment和DialpadFragment共用一个FramLayout

@+id/answer_and_dialpad_container

在显示的时候覆盖在CallCard的上层,比如CallCard中的photo(联系人头像)就是被dialpad给覆盖。

图2 VideoCallFragment ( 真人出境啦 )

左侧为普通视频电话,右侧为视频会议电话。

注意,虽然右侧看起来像是有4个小窗口显示内容,但实际上和左边一样只有两个控件显示视频,只不过右侧上方的视频内容被分成了3块。我们把黑色的背景色调成蓝色,就容易区分出是两个控件了。

至于为什么两张图incomingVideo的位置不一样,CallCard一个显示一个没显示,是因为,点击屏幕(或者等5s)后CallCard会隐藏,然后incomingVideo会自动调整位置到中央。

图3 AnswerFragment

更多的界面就不一一详细说明了。

如果你看到了不常见的控件,那它在代码中的位置,和临近位置的控件的代码位置也是临近的(有点拗口= =)。

2.3 InCallPresenter和InCallActivity

这个为什么要单独列成一条呢?因为这个Presenter比前面几个Presenter都重要,它连结这界面的各个部分。

InCallPresenter

从CallList中获取更新然后通知到InCallActivity,由InCallActivity控制界面显示。

同时各个Fragment和Presenter可以获得InCallPresenter的实例,进而更新/获得数据。 单独的Presenter负责对应的界面的逻辑,InCallPresenter负责整个界面的显示,协调各个Fragment/Presenter之间的工作。

以视频电话全屏为例,在VideoCallPresenter中有隐藏CallCard进入全屏模式的需求,在VideoCallPresenter中会通过InCallPresenter调用CallCardPresenter的onFullscreenModeChanged()方法,进而调用CallCardFragment的方法隐藏CallCard

InCallActivity

InCallActivity是InCallUI的主体,可以说所有的类都是围绕着或者是为了这个Activity工作的, 各个Fragment附着在InCallActivity上,InCallPresenter通过InCallActivity提供的 get***Fragmment的方法,获得具体Fragment对象, 更新界面。

Fragment是通过InCallActivity创建和显示的,但是各个Presenter和InCallPresenter之间的交互 不一定全都经过InCallActivity(比如可以通过listener调用)

图4 InCallUI基本架构

我们举两个例子 来说明界面上更新走过的流程:

1.设置CallStateLabel上的文本,比如"requesting video",代码的执行经过InCallPresenter> CallCardPresenter> CallCardFragment,跳过了InCallActivity;

2.弹出dialog,比如“网络不可用” ,代码执行经过IncallPresenter > InCallActivity

还有另外一个比较重要的没有体现在图上的类叫做 TelecomAdapter。

它的职责主要是把界面上操作的命令向下层传递,具体点就是把对call的操作传给Telecomm,包括接听,挂断,拒接,静音,切换audioRoute等。

3. Call的几种状态(对应phone状态)及上报流程

3.1 Call的状态

下面这张图不用记,知道有这么多就行了。

不同模块的call的状态不一样,有些能对应上,有些是独有的对应不上的。

比较重要的是InCallUI里的 Call.State和InCallPresenter的内部类 InCallState

InCallPresenter控制着界面显示,这里的InCallState就是界面显示的依据。

TelephonyManager向外提供访问手机状态的接口 ,只有三种状态。

图5 Call的状态

下图表现的是InCallUI Call状态的转化以及对应的TelephonyManager.CALL_STATE_***状态

图6 InCallUI 中的Call状态转化

其中CONNECTING/SELECT_PHONE_ACCOUNT这两个是 二者取其一。如果是双卡手机并设置每次询问,则拨号后的状态为SELECT_PHONE_ACCOUNT,如果有是单卡或者默认某一张卡拨打,则状态为CONNECTING,并且这个状态很短暂,很快就转换为DIALING。

3.2 上报流程

都是以 UNSOL_RESPONSE_CALL_STATE_CHANGED消息上报为开始,

//CS

09-09 10:52:42.093 D/RILJ    ( 4017): [UNSL]< UNSOL_RESPONSE_CALL_STATE_CHANGED [SUB1]//PS 07-18 15:31:58.120 

//PS

D/ImsSenderRxr( 4499): [UNSL]< UNSOL_RESPONSE_CALL_STATE_CHANGED  [id=1,DIALING,toa=129,norm,mo,0,voc,noevp,,cli=1,,3Call Details = 3 2 callSubState 0 videoPauseState2 mediaId0 Local Ability  Peer Ability  Cause code 0,CallFailCause Code= 501,CallFailCause String= null, ECT mask: 0] [SUB0]

流程中多次用到RegistrantList消息处理机制,比较关键的一个地方是TelephonyConnection里,在外拨(或者来电)设置连接的时候注册了一个消息

getPhone().registerForPreciseCallStateChanged(mHandler, MSG_PRECISE_CALL_STATE_CHANGED, null);当收到这个消息的时候会调用updateState()更新状态。

updateState

在Telephony更新call的状态的时候不同的状态对应不同的方法,如setActiveInternal()

图7 ims call state update(简图)

上图也印证了之前说的,虽然层次上packages叠在framework上面,但实际上他们并不是严格按照相邻的顺序去调用。有可能隔着一层就调用了,也可能反复调用。

下图以IMS电话接通状态上报为例

(图略)

图7 ims call state update(详图)

4. GSM与IMS MO流程的差异

  • 最大的区别是 IMS通话最后是通过高通私有代码ims.app中拨出去的。
  • IMS MO也要经过GSMPhone,判断到IMS网络可用以后会调用到ImsPhone中的dial()方法。
  • ImsSenderRxr.java相当于CS call中的RIL.java,DIAL的命令也是在此发送

07-18 15:35:04.977 D/ImsSenderRxr( 4499): [0247]> DIAL[SUB0]

  • ImsPhone中的log是在radio log中打印,但是ImsSenderRxr的log是在main log打印。
  • 在ImsPhone的后续步骤中,会创建ImsPhoneConnection和ImsCall。

对比图

(图略)

图8 GSM MO和IMS MO 对比(注:34画错了,不该指向ImsPhone,请读者忽略)

箭头指向为对应步骤,可以很明显的看到Ims的MO流程在这部分更复杂一些。针对IMS网络下的通话,专门建立了ImsPhoneConnection ImsCall。

5. 分析问题的常用log

5.1InCallUI

前面说过InCallUI的界面显示是以InCallState的状态为根据的,而查看InCallState的关键字是 Phone switching state:

14:42:29.721 I/InCall  (24960): InCallPresenter - Phone switching state: NO_CALLS -> NO_CALLS

14:42:29.864 I/InCall  (24960): InCallPresenter - Phone switching state: OUTGOING -> OUTGOING

14:42:30.262 I/InCall  (24960): InCallPresenter - Phone switching state: OUTGOING -> PENDING_OUTGOING

14:42:31.194 I/InCall  (24960): InCallPresenter - Phone switching state: PENDING_OUTGOING -> OUTGOING

14:42:34.975 I/InCall  (24960): InCallPresenter - Phone switching state: OUTGOING -> INCALL

14:42:35.630 I/InCall  (24960): InCallPresenter - Phone switching state: INCALL -> INCALL

InCallUI会根据这个状态显示界面信息。

这个状态一般是跟CallList里的call同步,但也有例外,就是会 撤回状态,关键字 Undo the state change

Log.i(this, "Undo the state change: " + newState + " -> " + mInCallState);

14:42:35.998 I/InCall  (24960): InCallPresenter – Undo the state change: INCOMING ->NO_CALLS

这时候就出现了界面显示和实际情况不一样,上面的log就对应来电没有界面。

注意 :INCALL包括DISCONNECTING和DISCONNECTED,虽然这两个是短暂的状态,但是看到的最后几个INCALL状态可能call已经断开了。

CallList中的onUpdate(),这是常见的看InCallUI中call的数量和状态的地方,关键字 CallList - onUpdate

17:13:21.514 I/InCall  ( 4166): CallList - onUpdate - [Call_0, CONNECTING, [Capabilities:

17:13:21.568 I/InCall  ( 4166): CallList - onUpdate - [Call_0, DIALING, [Capabilities: CAP

17:13:29.997 I/InCall  ( 4166): CallList - onUpdate - [Call_0, ACTIVE, [Capabilities: CAPA

17:13:30.255 I/InCall  ( 4166): CallList - onUpdate - [Call_0, ACTIVE, [Capabilities: CAPA

17:13:39.896 I/InCall  ( 4166): CallList - onUpdate - [Call_1, CONNECTING, [Capabilities:]

17:13:43.179 I/InCall  ( 4166): CallList - onUpdate - [Call_1, CONNECTING, [Capabilities:

17:13:43.266 I/InCall  ( 4166): CallList - onUpdate - [Call_1, DIALING, [Capabilities: CA

17:13:43.451 I/InCall  ( 4166): CallList - onUpdate - [Call_1, DIALING, [Capabilities: CA

17:13:43.471 I/InCall  ( 4166): CallList - onUpdate - [Call_0, ONHOLD, [Capabilities: CAP

17:13:43.492 I/InCall  ( 4166): CallList - onUpdate - [Call_0, ONHOLD, [Capabilities: CAP

5.2 Telecom

另外自android 6.0开始,Telecomm加了一个关键字为 Event 的log,会打印在Telecom内执行的关键步骤的log。打印出来如下

17:22:05.385 I/Telecom (  769): Event: Call 8: CREATED, null

17:22:05.394 I/Telecom (  769): Event: Call 8: SET_CONNECTING, ComponentInfo{com.android.phone/com.android.services.telephony.TelephonyConnectionService},

17:22:05.449 I/Telecom (  769): Event: Call 8: AUDIO_ROUTE, EARPIECE

17:22:09.161 I/Telecom (  769): Event: Call 8: BIND_CS, ComponentInfo{com.android.phone…

17:22:09.240 I/Telecom (  769): Event: Call 8: CS_BOUND, ComponentInfo{com.android.phone…

17:22:09.241 I/Telecom (  769): Event: Call 8: START_CONNECTION, tel:*****

17:22:09.399 I/Telecom (  769): Event: Call 8: SET_DIALING, successful outgoing call

17:22:17.395 I/Telecom (  769): Event: Call 8: SET_ACTIVE, active set explicitly

17:23:03.636 I/Telecom (  769): Event: Call 8: REQUEST_DISCONNECT, null

17:23:04.211 I/Telecom (  769): Event: Call 8: SET_DISCONNECTED, disconnected set explicitly> DisconnectCause [ Code: (LOCAL) Label: () Description: () Reason: (LOCAL) Tone: (27) ]

17:23:05.612 I/Telecom (  769): Event: Call 8: DESTROYED, null

DisconnectCause  是常用的查看通话断开原因的log。

注意:Telecom的log是在system_process进程打印,用adb命令抓log的时候要加上-b system

5.3 MT 来电

在main log中我常看

00:01:21.154 D/Telephony( 1389): PstnIncomingCallNotifier: handleNewRingingConnection

如果这条看不到还可以查CallsManager中的setCallState,可以从状态转化中看到来电状态。

14:42:34.888 I/Telecom ( 2920): CallsManager: setCallState DIALING -> ACTIVE, call: [100747014, DIALING,

5.4 MO DIAL

IMS(PS)

18:30:35.325 D/ImsSenderRxr( 3325): [0056]> DIAL[SUB0]

18:30:35.365 D/ImsSenderRxr( 3325): [0056]< DIAL [SUB0

有DIAL回传才表示拨号成功

GSM(CS)

17:29:56.206 D/RILJ    ( 4017): [6301]> DIAL [SUB1]

17:29:56.250 D/RILJ    ( 4017): [6301]< DIAL  [SUB1]

5.5 HANGUP

15:32:37.899 D/ImsSenderRxr( 4499): [0240]> HANGUP[SUB0]

15:32:37.995 D/ImsSenderRxr( 4499): [0240]< HANGUP [SUB0]

5.6 IMS

在IMS网络下通话的很多log是在main log中打印的,其中几个比较关键的类包括ImsSenderRxr、ImsServiceSub,以这两个类名为关键字在log中搜索就好了,或者以关键字/ImsSe把这两个一起搜出来

18:30:37.522 D/ImsSenderRxr( 3325): [UNSL]< UNSOL_RESPONSE_CALL_STATE_CHANGED  [id=1,DIALING,toa=129,norm,mo,0,voc,noevp,,cli=1,,3Call Details = 3 2 callSubState 0 videoPauseState2 mediaId5 Local Ability  Peer Ability  Cause code 0,CallFailCause Code= 0,CallFailCause String= null, ECT mask: 0] [SUB0]

18:30:37.522 D/ImsServiceSub( 3325): Message received: what = 1

18:30:37.522 D/ImsServiceSub( 3325): >handleCalls

18:30:37.523 D/ImsServiceSub( 3325): handleCalls: dc = id=1,DIALING,toa=129,norm,mo,0,voc,noevp,,cli=1,,3Call Details = 3 2 callSubState 0 videoPauseState2 mediaId5 Local Ability  Peer Ability  Cause code 0,CallFailCause Code= 0,CallFailCause String= null, ECT mask: 0

//CS

10:52:42.093 D/RILJ    ( 4017): [UNSL]< UNSOL_RESPONSE_CALL_STATE_CHANGED [SUB1]

//PS

15:31:58.120 D/ImsSenderRxr( 4499): [UNSL]< UNSOL_RESPONSE_CALL_STATE_CHANGED  [id=1,DIALING,toa=129,norm,mo,0,voc,noevp,,cli=1,,3Call Details = 3 2 callSubState 0 videoPauseState2 mediaId0 Local Ability  Peer Ability  Cause code 0,CallFailCause Code= 501,CallFailCause String= null, ECT mask: 0] [SUB0]

from:https://blog.csdn.net/aaa111/article/details/52876403

Dialer中界面组成、Call对象和log分析相关推荐

  1. 【Android 逆向】ART 脱壳 ( InMemoryDexClassLoader 脱壳 | dex_file.cc 中创建 DexFile 实例对象的相关函数分析 )

    文章目录 前言 一.dalvik_system_DexFile.cc#CreateDexFile 函数分析 二.dex_file.cc#DexFile::Open 函数分析 三.dex_file.cc ...

  2. kotlin半生对象_如何在Kotlin中使用Actor实现对象池

    kotlin半生对象 by osha1 由osha1 如何在Kotlin中使用Actor实现对象池 (How to implement an Object-Pool with an Actor in ...

  3. Android 7.1.1 Dialer中通话记录显示详解

    这两天在看通话记录相关问题,顺便跟踪了Dialer中的通话记录是怎么显示出来的,在这和大家分享下.当有来电或去电时,calllog会被插入到calllog.db的数据中去,具体可以参考<Andr ...

  4. 33 ES6中的类和对象

    技术交流QQ群:1027579432,欢迎你的加入! 欢迎关注我的微信公众号:CurryCoder的程序人生 1.面向对象 面向对象的思维特点: a.抽取(抽象)对象共有的属性和行为组织(封装)成一个 ...

  5. 12JavaScript中的内置对象

    技术交流QQ群:1027579432,欢迎你的加入! 1.内置对象 JavaScript中的对象分为3种:自定义对象.内置对象.浏览器对象: 前两种对象是JS中的基础内容,属于ECMAScript,第 ...

  6. jsp中的内置对象(9个)、作用

    jsp内置对象 定义:可以不加声明就在JSP页面脚本(Java程序片和Java表达式)中使用的成员变量 JSP共有以下9种基本内置组件(可与ASP的6种内部组件相对应): 1.request对象 客户 ...

  7. SpringMVC中通过@ResponseBody返回对象,Js中调用@ResponseBody返回值,统计剩余评论字数的js,@RequestParam默认值,@PathVariable的用法

    1.SpringMVC中通过@ResponseBody返回对象,作为JQuery中的ajax返回值 package com.kuman.cartoon.controller; import java. ...

  8. javascript中的内置对象和数据结构

    文章目录 简介 基础类型 undefined Boolean和Boolean对象 Number和BigInt String Symbol null Object Function Date Array ...

  9. SpringBoot 2.x yml 文件中自定义参数解析对象

    在SpringBoot中通过自定义参数可以实现很多重要的功能来达到解耦. SpringBoot 自定义参数的类型有: 简单键值对,自定义对象,数组,List,Map,List<Map> 1 ...

最新文章

  1. android 底部弹框 BottomSheetDialog 的使用
  2. FSMO角色以及DC修复
  3. Exchange日常管理之二十一:管理邮件归档
  4. python单例模式的五种实现方式
  5. 数据分析中的两种偏差
  6. Spring Cloud 服务安全连接 1
  7. android命名管道创建使用
  8. 数据科学包13-实例2:时间事件日志
  9. 【翻译】Tomcat 6.0 安装与启动
  10. JS思维导图类库:jsMind
  11. socket 由于目标计算机积极拒绝 无法连接,由于目标计算机积极拒绝,无法连接。 192.168.3.9:8081...
  12. 鸿蒙系统可以微信吗,鸿蒙系统可以用微信吗?微信鸿蒙版本下载-游戏大玩家...
  13. Revisiting The Lows
  14. PowerPC PPC460-S MMU(六 Shadow TLB)
  15. Redis安装、配置与相关优化
  16. 交互媒体技术—2D迷宫冒险游戏
  17. 聊聊前端工程化的实践与未来
  18. Windows server 2008 DNS服务器架构(八)
  19. LeetCode BackPack 背包问题
  20. 个人博客项目(1) --- 用户注册

热门文章

  1. vectorvn1610报价_VECTOR VN1610 CAN Network 通讯模块
  2. 《LKD3粗读笔记》(6)内核数据结构
  3. 【软考备战·希赛网每日一练】2023年4月28日
  4. 幻影路由服务器无响应,幻影D128路由器连不上网怎么办? | 192路由网
  5. HTTPS 方式访问网站
  6. 第一章笔记MySQL数据库的安装目录详解
  7. JuiceFS 在大搜车数据平台的实践
  8. wire与reg的区别?什么时候用wire?什么时候用reg?(转)
  9. (七十六):Masked Autoencoders Are Scalable Vision Learners
  10. Flutter 2.10 现已发布